make oaep and pss generic over keys

This commit is contained in:
dignifiedquire 2020-03-06 23:10:55 +01:00
parent 167080e2a4
commit 11500ed5e9
6 changed files with 52 additions and 69 deletions

View File

@ -110,13 +110,3 @@ pub fn generate_multi_prime_key<R: Rng>(
primes,
))
}
#[inline]
pub 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);
}

View File

@ -549,7 +549,7 @@ impl RSAPrivateKey {
pkcs1v15::decrypt::<ThreadRng, _>(None, self, ciphertext)
}
PaddingScheme::OAEP { mut digest, label } => {
oaep::decrypt::<ThreadRng>(None, self, ciphertext, &mut *digest, label)
oaep::decrypt::<ThreadRng, _>(None, self, ciphertext, &mut *digest, label)
}
_ => Err(Error::InvalidPaddingScheme),
}
@ -583,9 +583,14 @@ impl RSAPrivateKey {
mut salt_rng,
mut digest,
salt_len,
} => {
pss::sign::<_, ThreadRng>(&mut *salt_rng, None, self, input, salt_len, &mut *digest)
}
} => pss::sign::<_, ThreadRng, _>(
&mut *salt_rng,
None,
self,
input,
salt_len,
&mut *digest,
),
_ => Err(Error::InvalidPaddingScheme),
}
}
@ -607,7 +612,7 @@ impl RSAPrivateKey {
mut salt_rng,
mut digest,
salt_len,
} => pss::sign::<_, R>(
} => pss::sign::<_, R, _>(
&mut *salt_rng,
Some(rng),
self,

View File

@ -4,8 +4,7 @@ use digest::DynDigest;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use crate::errors::{Error, Result};
use crate::key::{self, PublicKey, PublicKeyParts, RSAPrivateKey};
use crate::raw::DecryptionPrimitive;
use crate::key::{self, PrivateKey, PublicKey};
fn inc_counter(counter: &mut [u8]) {
if counter[3] == u8::max_value() {
@ -109,7 +108,7 @@ pub fn encrypt<R: Rng, K: PublicKey>(
mgf1_xor(db, digest, seed);
mgf1_xor(seed, digest, db);
pub_key.raw_encryption_primitive(&em)
pub_key.raw_encryption_primitive(&em, pub_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from pkcs1# OAEP
@ -121,9 +120,9 @@ pub fn encrypt<R: Rng, K: PublicKey>(
/// forge signatures as if they had the private key. See
/// `decrypt_session_key` for a way of solving this problem.
#[inline]
pub fn decrypt<R: Rng>(
pub fn decrypt<R: Rng, SK: PrivateKey>(
rng: Option<&mut R>,
priv_key: &RSAPrivateKey,
priv_key: &SK,
ciphertext: &[u8],
digest: &mut dyn DynDigest,
label: Option<String>,
@ -145,9 +144,9 @@ pub fn decrypt<R: Rng>(
/// in order to maintain constant memory access patterns. If the plaintext was
/// valid then index contains the index of the original message in em.
#[inline]
fn decrypt_inner<R: Rng>(
fn decrypt_inner<R: Rng, SK: PrivateKey>(
rng: Option<&mut R>,
priv_key: &RSAPrivateKey,
priv_key: &SK,
ciphertext: &[u8],
digest: &mut dyn DynDigest,
label: Option<String>,
@ -163,7 +162,7 @@ fn decrypt_inner<R: Rng>(
return Err(Error::Decryption);
}
let mut em = priv_key.raw_decryption_primitive(rng, ciphertext)?;
let mut em = priv_key.raw_decryption_primitive(rng, ciphertext, priv_key.size())?;
let label = match label {
Some(l) => l,

View File

@ -3,14 +3,13 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use crate::errors::{Error, Result};
use crate::hash::Hash;
use crate::raw::{DecryptionPrimitive, EncryptionPrimitive};
use crate::key::{self, PrivateKey, PublicKey};
// Encrypts the given message with RSA and the padding
// scheme from PKCS#1 v1.5. The message must be no longer than the
// length of the public modulus minus 11 bytes.
#[inline]
pub fn encrypt<R: Rng>(rng: &mut R, pub_key: &RSAPublicKey, msg: &[u8]) -> Result<Vec<u8>> {
pub fn encrypt<R: Rng, PK: PublicKey>(rng: &mut R, pub_key: &PK, msg: &[u8]) -> Result<Vec<u8>> {
key::check_public(pub_key)?;
let k = pub_key.size();
@ -25,7 +24,7 @@ pub fn encrypt<R: Rng>(rng: &mut R, pub_key: &RSAPublicKey, msg: &[u8]) -> Resul
em[k - msg.len() - 1] = 0;
em[k - msg.len()..].copy_from_slice(msg);
pub_key.raw_encryption_primitive(&em)
pub_key.raw_encryption_primitive(&em, pub_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
@ -88,13 +87,13 @@ pub fn sign<R: Rng, SK: PrivateKey>(
em[k - t_len..k - hash_len].copy_from_slice(&prefix);
em[k - hash_len..k].copy_from_slice(hashed);
priv_key.raw_decryption_primitive(rng, &em)
priv_key.raw_decryption_primitive(rng, &em, priv_key.size())
}
/// Verifies an RSA PKCS#1 v1.5 signature.
#[inline]
pub fn verify(
pub_key: &RSAPublicKey,
pub fn verify<PK: PublicKey>(
pub_key: &PK,
hash: Option<&Hash>,
hashed: &[u8],
sig: &[u8],
@ -107,7 +106,7 @@ pub fn verify(
return Err(Error::Verification);
}
let em = pub_key.raw_encryption_primitive(sig)?;
let em = pub_key.raw_encryption_primitive(sig, pub_key.size())?;
// EM = 0x00 || 0x01 || PS || 0x00 || T
let mut ok = em[0].ct_eq(&0u8);
@ -160,7 +159,7 @@ fn decrypt_inner<R: Rng, SK: PrivateKey>(
return Err(Error::Decryption);
}
let em = priv_key.raw_decryption_primitive(rng, ciphertext)?;
let em = priv_key.raw_decryption_primitive(rng, ciphertext, priv_key.size())?;
let first_byte_is_zero = em[0].ct_eq(&0u8);
let second_byte_is_two = em[1].ct_eq(&2u8);
@ -219,7 +218,7 @@ mod tests {
use rand::thread_rng;
use sha1::{Digest, Sha1};
use crate::{Hash, PaddingScheme, PublicKey, RSAPublicKey};
use crate::{Hash, PaddingScheme, PublicKey, PublicKeyParts, RSAPrivateKey, RSAPublicKey};
#[test]
fn test_non_zero_bytes() {
@ -374,4 +373,4 @@ mod tests {
.verify(PaddingScheme::new_pkcs1v15(), msg, &sig)
.expect("failed to verify");
}
}

View File

@ -1,17 +1,14 @@
use std::vec::Vec;
use digest::DynDigest;
use num_bigint::BigUint;
use rand::{Rng, RngCore};
use subtle::ConstantTimeEq;
use crate::algorithms::copy_with_left_pad;
use crate::errors::{Error, Result};
use crate::internals;
use crate::key::{PublicKeyParts, RSAPrivateKey, RSAPublicKey};
use crate::key::{PrivateKey, PublicKey};
pub fn verify(
pub_key: &RSAPublicKey,
pub fn verify<PK: PublicKey>(
pub_key: &PK,
hashed: &[u8],
sig: &[u8],
digest: &mut dyn DynDigest,
@ -20,17 +17,10 @@ pub fn verify(
if sig.len() != (n_bits + 7) / 8 {
return Err(Error::Verification);
}
let s = BigUint::from_bytes_be(sig);
let m = internals::encrypt(pub_key, &s).to_bytes_be();
let em_bits = n_bits - 1;
let em_len = (em_bits + 7) / 8;
if em_len < m.len() {
return Err(Error::Verification);
}
let mut em = vec![0; em_len];
copy_with_left_pad(&mut em, &m);
let mut em = pub_key.raw_encryption_primitive(sig, em_len)?;
emsa_pss_verify(hashed, &mut em, em_bits, None, digest)
}
@ -39,10 +29,10 @@ pub fn verify(
/// Note that hashed must be the result of hashing the input message using the
/// given hash function. The opts argument may be nil, in which case sensible
/// defaults are used.
pub fn sign<T: RngCore + ?Sized, S: Rng>(
pub fn sign<T: RngCore + ?Sized, S: Rng, SK: PrivateKey>(
rng: &mut T,
blind_rng: Option<&mut S>,
priv_key: &RSAPrivateKey,
priv_key: &SK,
hashed: &[u8],
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
@ -60,9 +50,9 @@ pub fn sign<T: RngCore + ?Sized, S: Rng>(
/// Note that hashed must be the result of hashing the input message using the
/// given hash function. salt is a random sequence of bytes whose length will be
/// later used to verify the signature.
fn sign_pss_with_salt<T: Rng>(
fn sign_pss_with_salt<T: Rng, SK: PrivateKey>(
blind_rng: Option<&mut T>,
priv_key: &RSAPrivateKey,
priv_key: &SK,
hashed: &[u8],
salt: &[u8],
digest: &mut dyn DynDigest,
@ -71,14 +61,7 @@ fn sign_pss_with_salt<T: Rng>(
let mut em = vec![0; ((n_bits - 1) + 7) / 8];
emsa_pss_encode(&mut em, hashed, n_bits - 1, salt, digest)?;
let m = BigUint::from_bytes_be(&em);
let c = internals::decrypt_and_check(blind_rng, priv_key, &m)?.to_bytes_be();
let mut s = vec![0; (n_bits + 7) / 8];
copy_with_left_pad(&mut s, &c);
Ok(s)
priv_key.raw_decryption_primitive(blind_rng, &em, (n_bits + 7) / 8)
}
fn emsa_pss_encode(

View File

@ -2,13 +2,13 @@ use num_bigint::BigUint;
use rand::Rng;
use zeroize::Zeroize;
use crate::errors::Result;
use crate::errors::{Error, Result};
use crate::internals;
use crate::key::{PublicKeyParts, RSAPrivateKey, RSAPublicKey};
use crate::key::{RSAPrivateKey, RSAPublicKey};
pub trait EncryptionPrimitive {
/// Do NOT use directly! Only for implementors.
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>>;
fn raw_encryption_primitive(&self, plaintext: &[u8], pad_size: usize) -> Result<Vec<u8>>;
}
pub trait DecryptionPrimitive {
@ -17,15 +17,20 @@ pub trait DecryptionPrimitive {
&self,
rng: Option<&mut R>,
ciphertext: &[u8],
pad_size: usize,
) -> Result<Vec<u8>>;
}
impl EncryptionPrimitive for RSAPublicKey {
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
fn raw_encryption_primitive(&self, plaintext: &[u8], pad_size: usize) -> 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());
let ciphertext = internals::left_pad(&c_bytes, pad_size);
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}
// clear out tmp values
m.zeroize();
@ -37,8 +42,8 @@ impl EncryptionPrimitive for RSAPublicKey {
}
impl<'a> EncryptionPrimitive for &'a RSAPublicKey {
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
(*self).raw_encryption_primitive(plaintext)
fn raw_encryption_primitive(&self, plaintext: &[u8], pad_size: usize) -> Result<Vec<u8>> {
(*self).raw_encryption_primitive(plaintext, pad_size)
}
}
@ -47,11 +52,12 @@ impl DecryptionPrimitive for RSAPrivateKey {
&self,
rng: Option<&mut R>,
ciphertext: &[u8],
pad_size: usize,
) -> 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());
let plaintext = internals::left_pad(&m_bytes, pad_size);
// clear tmp values
c.zeroize();
@ -67,7 +73,8 @@ impl<'a> DecryptionPrimitive for &'a RSAPrivateKey {
&self,
rng: Option<&mut R>,
ciphertext: &[u8],
pad_size: usize,
) -> Result<Vec<u8>> {
(*self).raw_decryption_primitive(rng, ciphertext)
(*self).raw_decryption_primitive(rng, ciphertext, pad_size)
}
}