use cryptonum::unsigned::*; use digest::{Digest,FixedOutput}; use rsa::core::{drop0s,pkcs1_pad,xor_vecs}; use rsa::errors::RSAError; use rsa::oaep::OAEPParams; use rsa::signing_hashes::SigningHash; pub trait RSAPrivateKey { /// Generate a new private key using the given modulus and private /// exponent. You probably don't want to use this function directly /// unless you're writing your own key generation routine or key /// parsing library. fn new(n: N, d: N) -> Self; /// Sign the given message with the given private key. fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec; /// Decrypt the provided message using the given OAEP parameters. As /// mentioned in the comment for encryption, RSA decryption is really, /// really slow. So if your plaintext is larger than about half the /// bit size of the key, it's almost certainly a better idea to generate /// a fresh symmetric encryption key, encrypt only the key with RSA, and /// then encrypt the message with that key. fn decrypt(&self, oaep: &OAEPParams, msg: &[u8]) -> Result,RSAError> where H: Default + Digest + FixedOutput; } pub enum RSAPrivate { Key512(RSA512Private), Key1024(RSA1024Private), Key2048(RSA2048Private), Key3072(RSA3072Private), Key4096(RSA4096Private), Key8192(RSA8192Private), Key15360(RSA15360Private) } // fn print_vector(name: &'static str, bytes: &[u8]) // { // print!("{}: (length {}) ", name, bytes.len()); // for x in bytes.iter() { // print!("{:02X}", *x); // } // println!(""); // } macro_rules! generate_rsa_private { ($rsa: ident, $num: ident, $bar: ident, $size: expr) => { pub struct $rsa { pub(crate) nu: $bar, pub(crate) d: $num } impl RSAPrivateKey<$num> for $rsa { fn new(n: $num, d: $num) -> $rsa { let nu = $bar::new(n.clone()); $rsa { nu: nu, d: d } } fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec { let hash = (signhash.run)(msg); let em = pkcs1_pad(&signhash.ident, &hash, $size/8); let m = $num::from_bytes(&em); let s = self.sp1(&m); let sig = s.to_bytes(); sig } fn decrypt(&self, oaep: &OAEPParams, msg: &[u8]) -> Result,RSAError> where H: Default + Digest + FixedOutput { let mut res = Vec::new(); for chunk in msg.chunks($size/8) { let mut dchunk = self.oaep_decrypt(oaep, chunk)?; res.append(&mut dchunk); } Ok(res) } } impl $rsa { fn sp1(&self, m: &$num) -> $num { m.modexp(&self.d, &self.nu) } fn dp(&self, c: &$num) -> $num { c.modexp(&self.d, &self.nu) } fn oaep_decrypt(&self, oaep: &OAEPParams, c: &[u8]) -> Result,RSAError> where H: Default + Digest + FixedOutput { let byte_len = $size / 8; // Step 1b if c.len() != byte_len { return Err(RSAError::DecryptionError); } // Step 1c if byte_len < ((2 * oaep.hash_len()) + 2) { return Err(RSAError::DecryptHashMismatch); } // Step 2a let c_ip = $num::from_bytes(&c); // Step 2b let m_ip = self.dp(&c_ip); // Step 2c let em = m_ip.to_bytes(); // Step 3a let l_hash = oaep.hash(oaep.label.as_bytes()); // Step 3b let (y, rest) = em.split_at(1); let (masked_seed, masked_db) = rest.split_at(oaep.hash_len()); // Step 3c let seed_mask = oaep.mgf1(masked_db, oaep.hash_len()); // Step 3d let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask); // Step 3e let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1); // Step 3f let db = xor_vecs(&masked_db.to_vec(), &db_mask); // Step 3g let (l_hash2, ps_o_m) = db.split_at(oaep.hash_len()); let o_m = drop0s(ps_o_m); let (o, m) = o_m.split_at(1); // Checks! if o != [1] { return Err(RSAError::DecryptionError); } if l_hash != l_hash2 { return Err(RSAError::DecryptionError); } if y != [0] { return Err(RSAError::DecryptionError); } Ok(m.to_vec()) } } } } generate_rsa_private!(RSA512Private, U512, BarrettU512, 512); generate_rsa_private!(RSA1024Private, U1024, BarrettU1024, 1024); generate_rsa_private!(RSA2048Private, U2048, BarrettU2048, 2048); generate_rsa_private!(RSA3072Private, U3072, BarrettU3072, 3072); generate_rsa_private!(RSA4096Private, U4096, BarrettU4096, 4096); generate_rsa_private!(RSA8192Private, U8192, BarrettU8192, 8192); generate_rsa_private!(RSA15360Private, U15360, BarrettU15360, 15360); macro_rules! generate_tests { ( $( ($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) ),* ) => { $( #[cfg(test)] #[allow(non_snake_case)] mod $mod { use cryptonum::unsigned::Decoder; use super::*; use testing::run_test; use rsa::signing_hashes::*; use sha1::Sha1; use sha2::{Sha224,Sha256,Sha384,Sha512}; #[test] fn sign() { let fname = format!("tests/rsa/rsa{}.test", $size); run_test(fname.to_string(), 8, |case| { let (neg0, dbytes) = case.get("d").unwrap(); let (neg1, nbytes) = case.get("n").unwrap(); let (neg2, hbytes) = case.get("h").unwrap(); let (neg3, mbytes) = case.get("m").unwrap(); let (neg4, sbytes) = case.get("s").unwrap(); let (neg5, ubytes) = case.get("u").unwrap(); let (neg6, kbytes) = case.get("k").unwrap(); assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5&&!neg6); let n = $num64::from_bytes(nbytes); let nu = $num64::from_bytes(ubytes); let bigk = $num::from_bytes(kbytes); let k = usize::from(bigk); let d = $num::from_bytes(dbytes); let privkey = $rsa{ nu: $bar::from_components(k, n, nu), d: d }; let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16); let sighash = match hashnum { 0x160 => &SIGNING_HASH_SHA1, 0x224 => &SIGNING_HASH_SHA224, 0x256 => &SIGNING_HASH_SHA256, 0x384 => &SIGNING_HASH_SHA384, 0x512 => &SIGNING_HASH_SHA512, _ => panic!("Bad signing hash: {}", hashnum) }; let sig = privkey.sign(sighash, &mbytes); assert_eq!(sig, *sbytes); }); } #[test] fn decrypt() { let fname = format!("tests/rsa/rsa{}.test", $size); run_test(fname.to_string(), 8, |case| { let (neg0, dbytes) = case.get("d").unwrap(); let (neg1, nbytes) = case.get("n").unwrap(); let (neg2, hbytes) = case.get("h").unwrap(); let (neg3, mbytes) = case.get("m").unwrap(); let (neg4, cbytes) = case.get("c").unwrap(); let (neg5, ubytes) = case.get("u").unwrap(); let (neg6, kbytes) = case.get("k").unwrap(); assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5&&!neg6); let n = $num64::from_bytes(nbytes); let nu = $num64::from_bytes(ubytes); let bigk = $num::from_bytes(kbytes); let k = usize::from(bigk); let d = $num::from_bytes(dbytes); let privkey = $rsa{ nu: $bar::from_components(k, n, nu), d: d }; let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16); let empty = "".to_string(); match hashnum { 0x160 => { let oaep = OAEPParams::::new(empty); let plain = privkey.decrypt(&oaep, &cbytes); assert!(plain.is_ok()); assert_eq!(*mbytes, plain.unwrap()); } 0x224 =>{ let oaep = OAEPParams::::new(empty); let plain = privkey.decrypt(&oaep, &cbytes); assert!(plain.is_ok()); assert_eq!(*mbytes, plain.unwrap()); } 0x256 => { let oaep = OAEPParams::::new(empty); let plain = privkey.decrypt(&oaep, &cbytes); assert!(plain.is_ok()); assert_eq!(*mbytes, plain.unwrap()); } 0x384 => { let oaep = OAEPParams::::new(empty); let plain = privkey.decrypt(&oaep, &cbytes); assert!(plain.is_ok()); assert_eq!(*mbytes, plain.unwrap()); } 0x512 => { let oaep = OAEPParams::::new(empty); let plain = privkey.decrypt(&oaep, &cbytes); assert!(plain.is_ok()); assert_eq!(*mbytes, plain.unwrap()); } _ => panic!("Bad signing hash: {}", hashnum) }; }); } } )* } } generate_tests!( (RSA512, RSA512Private, U512, BarrettU512, U576, 512), (RSA1024, RSA1024Private, U1024, BarrettU1024, U1088, 1024), (RSA2048, RSA2048Private, U2048, BarrettU2048, U2112, 2048) // (RSA3072, RSA3072Private, U3072, BarrettU3072, U3136, 3072), // (RSA4096, RSA4096Private, U4096, BarrettU4096, U4160, 4096), // (RSA8192, RSA8192Private, U8192, BarrettU8192, U8256, 8192), // (RSA15360, RSA15360Private, U15360, BarrettU15360, U15424, 15360) );