Update some libraries, and now RSA works again!
This commit is contained in:
16
Cargo.toml
16
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<io::Error> for RSAError {
|
||||
fn from(e: io::Error) -> RSAError {
|
||||
impl From<rand::Error> for RSAError {
|
||||
fn from(e: rand::Error) -> RSAError {
|
||||
RSAError::RandomGenError(e)
|
||||
}
|
||||
}
|
||||
|
||||
126
src/rsa/mod.rs
126
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<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
|
||||
{
|
||||
($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<G: Rng>(rng: &mut G) -> $pair {
|
||||
pub fn generate<G>(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<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!(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: 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<H: Default + Input + FixedOutput> {
|
||||
pub struct OAEPParams<H: Default + Digest + FixedOutput> {
|
||||
pub label: String,
|
||||
phantom: PhantomData<H>
|
||||
}
|
||||
|
||||
impl<H: Default + Input + FixedOutput> OAEPParams<H> {
|
||||
impl<H: Default + Digest + FixedOutput> OAEPParams<H> {
|
||||
pub fn new(label: String)
|
||||
-> OAEPParams<H>
|
||||
{
|
||||
@@ -22,9 +22,7 @@ impl<H: Default + Input + FixedOutput> OAEPParams<H> {
|
||||
}
|
||||
|
||||
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
|
||||
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<u8> {
|
||||
@@ -35,8 +33,8 @@ impl<H: Default + Input + FixedOutput> OAEPParams<H> {
|
||||
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;
|
||||
|
||||
@@ -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<N> {
|
||||
/// then encrypt the message with that key.
|
||||
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,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<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,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<H>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where
|
||||
H: Default + Input + FixedOutput
|
||||
H: Default + Digest + FixedOutput
|
||||
{
|
||||
let byte_len = $size / 8;
|
||||
// Step 1b
|
||||
|
||||
@@ -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<N> {
|
||||
-> Result<Vec<u8>,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<N> {
|
||||
fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
|
||||
-> Result<Vec<u8>,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<Vec<u8>,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<Vec<u8>,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<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
|
||||
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
|
||||
// Step 2f
|
||||
|
||||
@@ -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<u8> {
|
||||
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<u8> {
|
||||
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<u8> {
|
||||
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<u8> {
|
||||
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<u8> {
|
||||
let mut d = Sha512::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
Sha512::digest(i).as_slice().to_vec()
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user