From 160618cdd71ef2e96ccceb917fd8912ad6f02bee Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Wed, 21 Nov 2018 22:27:59 -0800 Subject: [PATCH] Update some libraries, and now RSA works again! --- Cargo.toml | 16 ++--- src/lib.rs | 1 + src/rsa/errors.rs | 8 +-- src/rsa/mod.rs | 126 ++++++++++++++++++++++++++++++++------ src/rsa/oaep.rs | 14 ++--- src/rsa/private.rs | 12 ++-- src/rsa/public.rs | 23 ++++--- src/rsa/signing_hashes.rs | 22 ++----- 8 files changed, 151 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec79cc1..f246537 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,17 +9,17 @@ license-file = "LICENSE" repository = "https://github.com/acw/simple_crypto" [dependencies] -byteorder = "^1.2.3" +byteorder = "^1.2.7" cryptonum = { path = "../cryptonum" } -digest = "^0.7.1" -num = "^0.1.42" -rand = "^0.3" -sha-1 = "^0.7.0" -sha2 = "^0.7.0" -simple_asn1 = "^0.1.0" +digest = "^0.8.0" +num = "^0.2.0" +rand = "^0.6.0" +sha-1 = "^0.8.1" +sha2 = "^0.8.0" +simple_asn1 = "^0.2.0" [dev-dependencies] -quickcheck = "^0.4.1" +quickcheck = "^0.7.2" [profile.test] opt-level = 2 diff --git a/src/lib.rs b/src/lib.rs index 9f7544f..761a728 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ extern crate byteorder; extern crate cryptonum; extern crate digest; #[cfg(test)] +#[macro_use] extern crate quickcheck; extern crate num; extern crate rand; diff --git a/src/rsa/errors.rs b/src/rsa/errors.rs index aa860c1..3ced3c8 100644 --- a/src/rsa/errors.rs +++ b/src/rsa/errors.rs @@ -1,5 +1,5 @@ use simple_asn1::ASN1DecodeErr; -use std::io; +use rand; #[derive(Debug)] pub enum RSAError { @@ -8,12 +8,12 @@ pub enum RSAError { DecryptionError, DecryptHashMismatch, InvalidKey, - RandomGenError(io::Error), + RandomGenError(rand::Error), ASN1DecodeErr(ASN1DecodeErr) } -impl From for RSAError { - fn from(e: io::Error) -> RSAError { +impl From for RSAError { + fn from(e: rand::Error) -> RSAError { RSAError::RandomGenError(e) } } diff --git a/src/rsa/mod.rs b/src/rsa/mod.rs index c356a27..7199697 100644 --- a/src/rsa/mod.rs +++ b/src/rsa/mod.rs @@ -41,13 +41,27 @@ pub use self::public::{RSAPublic, RSAPublicKey, RSA3072Public, RSA4096Public, RSA8192Public, RSA15360Public}; -use cryptonum::signed::{ModInv}; +use cryptonum::signed::{EGCD,ModInv}; +use cryptonum::unsigned::{CryptoNum,PrimeGen}; use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360}; -use rand::Rng; +use rand::RngCore; +use std::ops::Sub; + +fn diff(a: &T, b: &T) -> T + where + T: Clone + PartialOrd, + T: Sub +{ + if a > b { + a.clone() - b.clone() + } else { + b.clone() - a.clone() + } +} macro_rules! generate_rsa_pair { - ($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident) => { + ($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident, $iterations: expr) => { pub struct $pair { pub public: $pub, pub private: $priv @@ -61,14 +75,17 @@ macro_rules! generate_rsa_pair } } - pub fn generate(rng: &mut G) -> $pair { + pub fn generate(rng: &mut G) -> $pair + where G: RngCore + { loop { - let e = $uint::from(65537u32); - let (p, q) = $pair::generate_pq(rng, &e); - let one: $half = $half::from(1u32); - let pminus1: $half = &p - &one; - let qminus1: $half = &q - &one; - let phi: $uint = pminus1 * qminus1; + let ebase = 65537u32; + let e = $uint::from(ebase); + let (p, q) = $pair::generate_pq(rng, &$half::from(ebase)); + let one = $half::from(1u32); + let pminus1 = &p - &one; + let qminus1 = &q - &one; + let phi = pminus1 * qminus1; let n = &p * &q; if let Some(d) = e.modinv(&phi) { let public = $pub::new(n.clone(), e); @@ -78,18 +95,89 @@ macro_rules! generate_rsa_pair } } - fn generate_pq(_rng: &mut G, _e: &$uint) -> ($half, $half) + fn generate_pq(rng: &mut G, e: &$half) -> ($half, $half) + where G: RngCore { - panic!("generate_pq") + let sqrt2_32 = 6074001000u64; + let half_bitlen = $half::bit_length(); + let minval = $half::from(sqrt2_32) << (half_bitlen - 33); + let mindiff = $half::from(1u64) << (half_bitlen - 101); + let p = $half::random_primef(rng, $iterations, |x| { + if (x >= minval) && x.gcd_is_one(e) { + Some(x) + } else { + None + } + }); + + loop { + let q = $half::random_primef(rng, $iterations, |x| { + if (x >= minval) && x.gcd_is_one(e) { + Some(x) + } else { + None + } + }); + + if diff(&p, &q) >= mindiff { + return (p, q); + } + } } } } } -generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256); -generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512); -generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024); -generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536); -generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048); -generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096); -generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680); +generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256, 7); +generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512, 7); +generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024, 4); +generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536, 3); +generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048, 3); +generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096, 3); +generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680, 3); + +#[cfg(test)] +mod generation { + use quickcheck::{Arbitrary,Gen}; + use std::fmt; + use super::*; + + impl Clone for RSA512KeyPair { + fn clone(&self) -> RSA512KeyPair { + RSA512KeyPair{ + public: RSA512Public { + n: self.public.n.clone(), + nu: self.public.nu.clone(), + e: self.public.e.clone(), + }, + private: RSA512Private { + nu: self.private.nu.clone(), + d: self.private.d.clone() + } + } + } + } + + impl fmt::Debug for RSA512KeyPair { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RSA512KeyPair") + .field("n", &self.public.n) + .field("e", &self.public.e) + .field("d", &self.private.d) + .finish() + } + } + + impl Arbitrary for RSA512KeyPair { + fn arbitrary(g: &mut G) -> RSA512KeyPair { + RSA512KeyPair::generate(g) + } + } + + quickcheck! { + fn generate_and_sign(keypair: RSA512KeyPair, msg: Vec) -> bool { + let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg); + keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig) + } + } +} \ No newline at end of file diff --git a/src/rsa/oaep.rs b/src/rsa/oaep.rs index 8b76e70..e8612f1 100644 --- a/src/rsa/oaep.rs +++ b/src/rsa/oaep.rs @@ -1,16 +1,16 @@ use byteorder::{BigEndian,ByteOrder}; -use digest::{FixedOutput,Input}; +use digest::{Digest,FixedOutput}; use std::marker::PhantomData; /// Parameters for OAEP encryption and decryption: a hash function to use as /// part of the message generation function (MGF1, if you're curious), /// and any labels you want to include as part of the encryption. -pub struct OAEPParams { +pub struct OAEPParams { pub label: String, phantom: PhantomData } -impl OAEPParams { +impl OAEPParams { pub fn new(label: String) -> OAEPParams { @@ -22,9 +22,7 @@ impl OAEPParams { } pub fn hash(&self, input: &[u8]) -> Vec { - let mut digest = H::default(); - digest.process(input); - digest.fixed_result().as_slice().to_vec() + H::digest(input).as_slice().to_vec() } pub fn mgf1(&self, input: &[u8], len: usize) -> Vec { @@ -35,8 +33,8 @@ impl OAEPParams { let mut buffer = [0; 4]; BigEndian::write_u32(&mut buffer, counter); let mut digest = H::default(); - digest.process(input); - digest.process(&buffer); + digest.input(input); + digest.input(&buffer); let chunk = digest.fixed_result(); res.extend_from_slice(chunk.as_slice()); counter = counter + 1; diff --git a/src/rsa/private.rs b/src/rsa/private.rs index 3f50ef6..e293795 100644 --- a/src/rsa/private.rs +++ b/src/rsa/private.rs @@ -1,5 +1,5 @@ use cryptonum::unsigned::*; -use digest::{FixedOutput,Input}; +use digest::{Digest,FixedOutput}; use rsa::core::{drop0s,pkcs1_pad,xor_vecs}; use rsa::errors::RSAError; use rsa::oaep::OAEPParams; @@ -23,7 +23,7 @@ pub trait RSAPrivateKey { /// then encrypt the message with that key. fn decrypt(&self, oaep: &OAEPParams, msg: &[u8]) -> Result,RSAError> - where H: Default + Input + FixedOutput; + where H: Default + Digest + FixedOutput; } pub enum RSAPrivate { @@ -49,8 +49,8 @@ macro_rules! generate_rsa_private { ($rsa: ident, $num: ident, $bar: ident, $size: expr) => { pub struct $rsa { - nu: $bar, - d: $num + pub(crate) nu: $bar, + pub(crate) d: $num } impl RSAPrivateKey<$num> for $rsa { @@ -72,7 +72,7 @@ macro_rules! generate_rsa_private fn decrypt(&self, oaep: &OAEPParams, msg: &[u8]) -> Result,RSAError> - where H: Default + Input + FixedOutput + where H: Default + Digest + FixedOutput { let mut res = Vec::new(); @@ -97,7 +97,7 @@ macro_rules! generate_rsa_private fn oaep_decrypt(&self, oaep: &OAEPParams, c: &[u8]) -> Result,RSAError> where - H: Default + Input + FixedOutput + H: Default + Digest + FixedOutput { let byte_len = $size / 8; // Step 1b diff --git a/src/rsa/public.rs b/src/rsa/public.rs index 67c2ab9..dd9458d 100644 --- a/src/rsa/public.rs +++ b/src/rsa/public.rs @@ -1,7 +1,8 @@ use cryptonum::unsigned::*; -use digest::{FixedOutput,Input}; +use digest::{Digest,FixedOutput}; use num::BigInt; -use rand::{OsRng,Rng}; +use rand::Rng; +use rand::rngs::OsRng; use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs}; use rsa::errors::RSAError; use rsa::oaep::OAEPParams; @@ -40,7 +41,7 @@ pub trait RSAPublicKey { -> Result,RSAError> where G: Rng, - H: Default + Input + FixedOutput; + H: Default + Digest + FixedOutput; /// Encrypt the message with a hash function, given the appropriate /// label. Please note that RSA encryption is not particularly fast, @@ -53,7 +54,7 @@ pub trait RSAPublicKey { fn encrypt(&self,oaep:&OAEPParams,msg:&[u8]) -> Result,RSAError> where - H: Default + Input + FixedOutput + H: Default + Digest + FixedOutput { let mut g = OsRng::new()?; self.encrypt_rng(&mut g, oaep, msg) @@ -177,9 +178,9 @@ macro_rules! generate_rsa_public ($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => { #[derive(PartialEq)] pub struct $rsa { - n: $num, - nu: $bar, - e: $num + pub(crate) n: $num, + pub(crate) nu: $bar, + pub(crate) e: $num } impl RSAPublicKey<$num> for $rsa { @@ -203,7 +204,7 @@ macro_rules! generate_rsa_public -> Result,RSAError> where G: Rng, - H: Default + Input + FixedOutput + H: Default + Digest + FixedOutput { let byte_len = $size / 8; let mut res = Vec::new(); @@ -233,7 +234,7 @@ macro_rules! generate_rsa_public -> Result,RSAError> where G: Rng, - H: Default + Input + FixedOutput + H: Default + Digest + FixedOutput { let byte_len = $size / 8; // Step 1b @@ -253,7 +254,9 @@ macro_rules! generate_rsa_public db.push(1); db.extend_from_slice(m); // Step 2d - let seed : Vec = g.gen_iter().take(oaep.hash_len()).collect(); + let mut seed: Vec = Vec::with_capacity(oaep.hash_len()); + seed.resize(oaep.hash_len(), 0); + g.fill(seed.as_mut_slice()); // Step 2e let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1); // Step 2f diff --git a/src/rsa/signing_hashes.rs b/src/rsa/signing_hashes.rs index 0b40955..cc0d965 100644 --- a/src/rsa/signing_hashes.rs +++ b/src/rsa/signing_hashes.rs @@ -1,4 +1,4 @@ -use digest::{FixedOutput,Input}; +use digest::Digest; use sha1::Sha1; use sha2::{Sha224,Sha256,Sha384,Sha512}; use std::fmt; @@ -46,9 +46,7 @@ pub static SIGNING_HASH_SHA1: SigningHash = SigningHash { }; fn runsha1(i: &[u8]) -> Vec { - let mut d = Sha1::default(); - d.process(i); - d.fixed_result().as_slice().to_vec() + Sha1::digest(i).as_slice().to_vec() } /// Sign a hash based on SHA2-224. This is the first reasonable choice @@ -63,9 +61,7 @@ pub static SIGNING_HASH_SHA224: SigningHash = SigningHash { }; fn runsha224(i: &[u8]) -> Vec { - let mut d = Sha224::default(); - d.process(i); - d.fixed_result().as_slice().to_vec() + Sha224::digest(i).as_slice().to_vec() } /// Sign a hash based on SHA2-256. The first one I'd recommend! @@ -78,9 +74,7 @@ pub static SIGNING_HASH_SHA256: SigningHash = SigningHash { }; fn runsha256(i: &[u8]) -> Vec { - let mut d = Sha256::default(); - d.process(i); - d.fixed_result().as_slice().to_vec() + Sha256::digest(i).as_slice().to_vec() } /// Sign a hash based on SHA2-384. Approximately 50% better than @@ -94,9 +88,7 @@ pub static SIGNING_HASH_SHA384: SigningHash = SigningHash { }; fn runsha384(i: &[u8]) -> Vec { - let mut d = Sha384::default(); - d.process(i); - d.fixed_result().as_slice().to_vec() + Sha384::digest(i).as_slice().to_vec() } /// Sign a hash based on SHA2-512. At this point, you're getting a bit @@ -111,9 +103,7 @@ pub static SIGNING_HASH_SHA512: SigningHash = SigningHash { }; fn runsha512(i: &[u8]) -> Vec { - let mut d = Sha512::default(); - d.process(i); - d.fixed_result().as_slice().to_vec() + Sha512::digest(i).as_slice().to_vec() }