Update some libraries, and now RSA works again!

This commit is contained in:
2018-11-21 22:27:59 -08:00
parent 9d87916cc5
commit 160618cdd7
8 changed files with 151 additions and 71 deletions

View File

@@ -9,17 +9,17 @@ license-file = "LICENSE"
repository = "https://github.com/acw/simple_crypto" repository = "https://github.com/acw/simple_crypto"
[dependencies] [dependencies]
byteorder = "^1.2.3" byteorder = "^1.2.7"
cryptonum = { path = "../cryptonum" } cryptonum = { path = "../cryptonum" }
digest = "^0.7.1" digest = "^0.8.0"
num = "^0.1.42" num = "^0.2.0"
rand = "^0.3" rand = "^0.6.0"
sha-1 = "^0.7.0" sha-1 = "^0.8.1"
sha2 = "^0.7.0" sha2 = "^0.8.0"
simple_asn1 = "^0.1.0" simple_asn1 = "^0.2.0"
[dev-dependencies] [dev-dependencies]
quickcheck = "^0.4.1" quickcheck = "^0.7.2"
[profile.test] [profile.test]
opt-level = 2 opt-level = 2

View File

@@ -13,6 +13,7 @@ extern crate byteorder;
extern crate cryptonum; extern crate cryptonum;
extern crate digest; extern crate digest;
#[cfg(test)] #[cfg(test)]
#[macro_use]
extern crate quickcheck; extern crate quickcheck;
extern crate num; extern crate num;
extern crate rand; extern crate rand;

View File

@@ -1,5 +1,5 @@
use simple_asn1::ASN1DecodeErr; use simple_asn1::ASN1DecodeErr;
use std::io; use rand;
#[derive(Debug)] #[derive(Debug)]
pub enum RSAError { pub enum RSAError {
@@ -8,12 +8,12 @@ pub enum RSAError {
DecryptionError, DecryptionError,
DecryptHashMismatch, DecryptHashMismatch,
InvalidKey, InvalidKey,
RandomGenError(io::Error), RandomGenError(rand::Error),
ASN1DecodeErr(ASN1DecodeErr) ASN1DecodeErr(ASN1DecodeErr)
} }
impl From<io::Error> for RSAError { impl From<rand::Error> for RSAError {
fn from(e: io::Error) -> RSAError { fn from(e: rand::Error) -> RSAError {
RSAError::RandomGenError(e) RSAError::RandomGenError(e)
} }
} }

View File

@@ -41,13 +41,27 @@ pub use self::public::{RSAPublic, RSAPublicKey,
RSA3072Public, RSA4096Public, RSA8192Public, RSA3072Public, RSA4096Public, RSA8192Public,
RSA15360Public}; 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 cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
use rand::Rng; use rand::RngCore;
use std::ops::Sub;
fn diff<T>(a: &T, b: &T) -> T
where
T: Clone + PartialOrd,
T: Sub<T,Output=T>
{
if a > b {
a.clone() - b.clone()
} else {
b.clone() - a.clone()
}
}
macro_rules! generate_rsa_pair 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 struct $pair {
pub public: $pub, pub public: $pub,
pub private: $priv pub private: $priv
@@ -61,14 +75,17 @@ macro_rules! generate_rsa_pair
} }
} }
pub fn generate<G: Rng>(rng: &mut G) -> $pair { pub fn generate<G>(rng: &mut G) -> $pair
where G: RngCore
{
loop { loop {
let e = $uint::from(65537u32); let ebase = 65537u32;
let (p, q) = $pair::generate_pq(rng, &e); let e = $uint::from(ebase);
let one: $half = $half::from(1u32); let (p, q) = $pair::generate_pq(rng, &$half::from(ebase));
let pminus1: $half = &p - &one; let one = $half::from(1u32);
let qminus1: $half = &q - &one; let pminus1 = &p - &one;
let phi: $uint = pminus1 * qminus1; let qminus1 = &q - &one;
let phi = pminus1 * qminus1;
let n = &p * &q; let n = &p * &q;
if let Some(d) = e.modinv(&phi) { if let Some(d) = e.modinv(&phi) {
let public = $pub::new(n.clone(), e); let public = $pub::new(n.clone(), e);
@@ -78,18 +95,89 @@ macro_rules! generate_rsa_pair
} }
} }
fn generate_pq<G: Rng>(_rng: &mut G, _e: &$uint) -> ($half, $half) fn generate_pq<G>(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!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256, 7);
generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512); generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512, 7);
generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024); generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024, 4);
generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536); generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536, 3);
generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048); generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048, 3);
generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096); generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096, 3);
generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680); 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: Gen>(g: &mut G) -> RSA512KeyPair {
RSA512KeyPair::generate(g)
}
}
quickcheck! {
fn generate_and_sign(keypair: RSA512KeyPair, msg: Vec<u8>) -> bool {
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
}
}
}

View File

@@ -1,16 +1,16 @@
use byteorder::{BigEndian,ByteOrder}; use byteorder::{BigEndian,ByteOrder};
use digest::{FixedOutput,Input}; use digest::{Digest,FixedOutput};
use std::marker::PhantomData; use std::marker::PhantomData;
/// Parameters for OAEP encryption and decryption: a hash function to use as /// Parameters for OAEP encryption and decryption: a hash function to use as
/// part of the message generation function (MGF1, if you're curious), /// part of the message generation function (MGF1, if you're curious),
/// and any labels you want to include as part of the encryption. /// and any labels you want to include as part of the encryption.
pub struct OAEPParams<H: Default + Input + FixedOutput> { pub struct OAEPParams<H: Default + Digest + FixedOutput> {
pub label: String, pub label: String,
phantom: PhantomData<H> phantom: PhantomData<H>
} }
impl<H: Default + Input + FixedOutput> OAEPParams<H> { impl<H: Default + Digest + FixedOutput> OAEPParams<H> {
pub fn new(label: String) pub fn new(label: String)
-> OAEPParams<H> -> OAEPParams<H>
{ {
@@ -22,9 +22,7 @@ impl<H: Default + Input + FixedOutput> OAEPParams<H> {
} }
pub fn hash(&self, input: &[u8]) -> Vec<u8> { pub fn hash(&self, input: &[u8]) -> Vec<u8> {
let mut digest = H::default(); H::digest(input).as_slice().to_vec()
digest.process(input);
digest.fixed_result().as_slice().to_vec()
} }
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> { pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
@@ -35,8 +33,8 @@ impl<H: Default + Input + FixedOutput> OAEPParams<H> {
let mut buffer = [0; 4]; let mut buffer = [0; 4];
BigEndian::write_u32(&mut buffer, counter); BigEndian::write_u32(&mut buffer, counter);
let mut digest = H::default(); let mut digest = H::default();
digest.process(input); digest.input(input);
digest.process(&buffer); digest.input(&buffer);
let chunk = digest.fixed_result(); let chunk = digest.fixed_result();
res.extend_from_slice(chunk.as_slice()); res.extend_from_slice(chunk.as_slice());
counter = counter + 1; counter = counter + 1;

View File

@@ -1,5 +1,5 @@
use cryptonum::unsigned::*; use cryptonum::unsigned::*;
use digest::{FixedOutput,Input}; use digest::{Digest,FixedOutput};
use rsa::core::{drop0s,pkcs1_pad,xor_vecs}; use rsa::core::{drop0s,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError; use rsa::errors::RSAError;
use rsa::oaep::OAEPParams; use rsa::oaep::OAEPParams;
@@ -23,7 +23,7 @@ pub trait RSAPrivateKey<N> {
/// then encrypt the message with that key. /// then encrypt the message with that key.
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8]) fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where H: Default + Input + FixedOutput; where H: Default + Digest + FixedOutput;
} }
pub enum RSAPrivate { pub enum RSAPrivate {
@@ -49,8 +49,8 @@ macro_rules! generate_rsa_private
{ {
($rsa: ident, $num: ident, $bar: ident, $size: expr) => { ($rsa: ident, $num: ident, $bar: ident, $size: expr) => {
pub struct $rsa { pub struct $rsa {
nu: $bar, pub(crate) nu: $bar,
d: $num pub(crate) d: $num
} }
impl RSAPrivateKey<$num> for $rsa { impl RSAPrivateKey<$num> for $rsa {
@@ -72,7 +72,7 @@ macro_rules! generate_rsa_private
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8]) fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where H: Default + Input + FixedOutput where H: Default + Digest + FixedOutput
{ {
let mut res = Vec::new(); let mut res = Vec::new();
@@ -97,7 +97,7 @@ macro_rules! generate_rsa_private
fn oaep_decrypt<H>(&self, oaep: &OAEPParams<H>, c: &[u8]) fn oaep_decrypt<H>(&self, oaep: &OAEPParams<H>, c: &[u8])
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where where
H: Default + Input + FixedOutput H: Default + Digest + FixedOutput
{ {
let byte_len = $size / 8; let byte_len = $size / 8;
// Step 1b // Step 1b

View File

@@ -1,7 +1,8 @@
use cryptonum::unsigned::*; use cryptonum::unsigned::*;
use digest::{FixedOutput,Input}; use digest::{Digest,FixedOutput};
use num::BigInt; 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::core::{decode_biguint,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError; use rsa::errors::RSAError;
use rsa::oaep::OAEPParams; use rsa::oaep::OAEPParams;
@@ -40,7 +41,7 @@ pub trait RSAPublicKey<N> {
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where where
G: Rng, G: Rng,
H: Default + Input + FixedOutput; H: Default + Digest + FixedOutput;
/// Encrypt the message with a hash function, given the appropriate /// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast, /// label. Please note that RSA encryption is not particularly fast,
@@ -53,7 +54,7 @@ pub trait RSAPublicKey<N> {
fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8]) fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where where
H: Default + Input + FixedOutput H: Default + Digest + FixedOutput
{ {
let mut g = OsRng::new()?; let mut g = OsRng::new()?;
self.encrypt_rng(&mut g, oaep, msg) 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) => { ($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => {
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct $rsa { pub struct $rsa {
n: $num, pub(crate) n: $num,
nu: $bar, pub(crate) nu: $bar,
e: $num pub(crate) e: $num
} }
impl RSAPublicKey<$num> for $rsa { impl RSAPublicKey<$num> for $rsa {
@@ -203,7 +204,7 @@ macro_rules! generate_rsa_public
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where where
G: Rng, G: Rng,
H: Default + Input + FixedOutput H: Default + Digest + FixedOutput
{ {
let byte_len = $size / 8; let byte_len = $size / 8;
let mut res = Vec::new(); let mut res = Vec::new();
@@ -233,7 +234,7 @@ macro_rules! generate_rsa_public
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where where
G: Rng, G: Rng,
H: Default + Input + FixedOutput H: Default + Digest + FixedOutput
{ {
let byte_len = $size / 8; let byte_len = $size / 8;
// Step 1b // Step 1b
@@ -253,7 +254,9 @@ macro_rules! generate_rsa_public
db.push(1); db.push(1);
db.extend_from_slice(m); db.extend_from_slice(m);
// Step 2d // Step 2d
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect(); let mut seed: Vec<u8> = Vec::with_capacity(oaep.hash_len());
seed.resize(oaep.hash_len(), 0);
g.fill(seed.as_mut_slice());
// Step 2e // Step 2e
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1); let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
// Step 2f // Step 2f

View File

@@ -1,4 +1,4 @@
use digest::{FixedOutput,Input}; use digest::Digest;
use sha1::Sha1; use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512}; use sha2::{Sha224,Sha256,Sha384,Sha512};
use std::fmt; use std::fmt;
@@ -46,9 +46,7 @@ pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
}; };
fn runsha1(i: &[u8]) -> Vec<u8> { fn runsha1(i: &[u8]) -> Vec<u8> {
let mut d = Sha1::default(); Sha1::digest(i).as_slice().to_vec()
d.process(i);
d.fixed_result().as_slice().to_vec()
} }
/// Sign a hash based on SHA2-224. This is the first reasonable choice /// 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<u8> { fn runsha224(i: &[u8]) -> Vec<u8> {
let mut d = Sha224::default(); Sha224::digest(i).as_slice().to_vec()
d.process(i);
d.fixed_result().as_slice().to_vec()
} }
/// Sign a hash based on SHA2-256. The first one I'd recommend! /// 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<u8> { fn runsha256(i: &[u8]) -> Vec<u8> {
let mut d = Sha256::default(); Sha256::digest(i).as_slice().to_vec()
d.process(i);
d.fixed_result().as_slice().to_vec()
} }
/// Sign a hash based on SHA2-384. Approximately 50% better than /// 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<u8> { fn runsha384(i: &[u8]) -> Vec<u8> {
let mut d = Sha384::default(); Sha384::digest(i).as_slice().to_vec()
d.process(i);
d.fixed_result().as_slice().to_vec()
} }
/// Sign a hash based on SHA2-512. At this point, you're getting a bit /// 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<u8> { fn runsha512(i: &[u8]) -> Vec<u8> {
let mut d = Sha512::default(); Sha512::digest(i).as_slice().to_vec()
d.process(i);
d.fixed_result().as_slice().to_vec()
} }