Files
simple_crypto/src/rsa/public.rs

125 lines
4.3 KiB
Rust

use cryptonum::{BarrettUCN,UCN};
use digest::{FixedOutput,Input};
use rand::{OsRng,Rng};
use rsa::core::{ACCEPTABLE_KEY_SIZES,ep,pkcs1_pad,vp1,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct RSAPublic {
pub(crate) byte_len: usize,
pub(crate) n: UCN,
pub(crate) nu: BarrettUCN,
pub(crate) e: UCN
}
impl RSAPublic {
/// Create a new RSA public key from the given components, which you found
/// via some other mechanism.
pub fn new(n: UCN, e: UCN) -> RSAPublic {
let len = n.bits();
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
if valid_bits >= len {
return RSAPublic{
byte_len: valid_bits / 8,
n: n.clone(),
nu: n.barrett_u(),
e: e.clone()
};
}
}
panic!("Invalid RSA key size in new()")
}
/// Verify the signature for a given message, using the given signing hash,
/// returning true iff the signature validates.
pub fn verify(&self, shash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool {
let hash = (shash.run)(msg);
let s = UCN::from_bytes(&sig);
let m = vp1(&self.nu, &self.e, &s);
let em = m.to_bytes(self.byte_len);
let em_ = pkcs1_pad(&shash.ident, &hash, self.byte_len);
(em == em_)
}
/// Encrypt the given data with the public key and parameters, returning
/// the encrypted blob or an error encountered during encryption.
///
/// OAEP encoding is used for this process, which requires a random number
/// generator. This version of the function uses `OsRng`. If you want to
/// use your own RNG, use `encrypt_w_rng`.
pub fn encrypt<H:Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
{
let mut g = OsRng::new()?;
self.encrypt_with_rng(&mut g, oaep, msg)
}
/// Encrypt the given data with the public key and parameters, returning
/// the encrypted blob or an error encountered during encryption. This
/// version also allows you to provide your own RNG, if you really feel
/// like shooting yourself in the foot.
pub fn encrypt_with_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where G: Rng, H: Clone + Input + FixedOutput
{
if self.byte_len <= ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::KeyTooSmallForHash);
}
let mut res = Vec::new();
for chunk in msg.chunks(self.byte_len - (2 * oaep.hash_len()) - 2) {
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
res.append(&mut newchunk)
}
Ok(res)
}
fn oaep_encrypt<G: Rng,H:Clone + Input + FixedOutput>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
{
// Step 1b
if msg.len() > (self.byte_len - (2 * oaep.hash_len()) - 2) {
return Err(RSAError::BadMessageSize)
}
// Step 2a
let mut lhash = oaep.hash(oaep.label.as_bytes());
// Step 2b
let num0s = self.byte_len - msg.len() - (2 * oaep.hash_len()) - 2;
let mut ps = Vec::new();
ps.resize(num0s, 0);
// Step 2c
let mut db = Vec::new();
db.append(&mut lhash);
db.append(&mut ps);
db.push(1);
db.extend_from_slice(msg);
// Step 2d
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
// Step 2e
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
// Step 2f
let mut masked_db = xor_vecs(&db, &db_mask);
// Step 2g
let seed_mask = oaep.mgf1(&masked_db, oaep.hash_len());
// Step 2h
let mut masked_seed = xor_vecs(&seed, &seed_mask);
// Step 2i
let mut em = Vec::new();
em.push(0);
em.append(&mut masked_seed);
em.append(&mut masked_db);
// Step 3a
let m_i = UCN::from_bytes(&em);
// Step 3b
let c_i = ep(&self.nu, &self.e, &m_i);
// Step 3c
let c = c_i.to_bytes(self.byte_len);
Ok(c)
}
}