From 026b321f7ca73405c16b10fb795a18e087cf8808 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sat, 13 Apr 2019 15:53:17 -0700 Subject: [PATCH 1/5] Remove the DSAPubKey/DSAPublicKey split. --- src/dsa/mod.rs | 14 +++++++------- src/dsa/private.rs | 40 ++++++++++------------------------------ src/dsa/public.rs | 39 +++++++++++---------------------------- src/dsa/tests.rs | 12 ++++++------ src/ssh/dsa.rs | 6 +++--- src/ssh/mod.rs | 4 ++-- src/x509/mod.rs | 2 +- src/x509/publickey.rs | 10 +++++----- 8 files changed, 45 insertions(+), 82 deletions(-) diff --git a/src/dsa/mod.rs b/src/dsa/mod.rs index 54ae7e5..94de91f 100644 --- a/src/dsa/mod.rs +++ b/src/dsa/mod.rs @@ -17,16 +17,16 @@ use super::KeyPair; pub struct DSAKeyPair { - pub private: DSAPrivKey

, - pub public: DSAPubKey

+ pub private: DSAPrivateKey

, + pub public: DSAPublicKey

} impl KeyPair for DSAKeyPair

{ - type Private = DSAPrivKey

; - type Public = DSAPubKey

; + type Private = DSAPrivateKey

; + type Public = DSAPublicKey

; - fn new(public: DSAPubKey

, private: DSAPrivKey

) -> DSAKeyPair

+ fn new(public: DSAPublicKey

, private: DSAPrivateKey

) -> DSAKeyPair

{ DSAKeyPair{ private, public } } @@ -67,8 +67,8 @@ macro_rules! generate_dsa_pair { // 7. y = g^x mod p let y = params.g.modexp(&$ltype::from(&x), ¶ms.p); // 8. Return SUCCESS, x, and y. - let private = DSAPrivKey::new(params.clone(), x); - let public = DSAPubKey::new(params.clone(), y); + let private = DSAPrivateKey::<$ptype>::new(params.clone(), x); + let public = DSAPublicKey::<$ptype>::new(params.clone(), y); DSAKeyPair { private, public } } } diff --git a/src/dsa/private.rs b/src/dsa/private.rs index 84ec652..cc7400e 100644 --- a/src/dsa/private.rs +++ b/src/dsa/private.rs @@ -5,49 +5,29 @@ use dsa::params::*; use dsa::rfc6979::*; use hmac::{Hmac,Mac}; -pub trait DSAPrivateKey { - type Params; - type L; - type N; - - /// Generate a new private key using the given DSA parameters and private - /// key value. - fn new(params: Self::Params, x: Self::N) -> Self; - /// Generate a DSA signature for the given message, using the appropriate - /// hash included in the type invocation. - fn sign(&self, m: &[u8]) -> DSASignature - where - Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, - Hmac: Mac; -} - -pub struct DSAPrivKey +pub struct DSAPrivateKey { pub(crate) params: Params, pub(crate) x: Params::N } pub enum DSAPrivate { - DSA1024Private(DSAPrivKey), - DSA2048SmallPrivate(DSAPrivKey), - DSA2048Private(DSAPrivKey), - DSA3072Private(DSAPrivKey) + DSA1024Private(DSAPrivateKey), + DSA2048SmallPrivate(DSAPrivateKey), + DSA2048Private(DSAPrivateKey), + DSA3072Private(DSAPrivateKey) } macro_rules! privkey_impls { ($ptype: ident, $ltype: ident, $ntype: ident, $big: ident, $bigger: ident, $biggest: ident) => { - impl DSAPrivateKey for DSAPrivKey<$ptype> + impl DSAPrivateKey<$ptype> { - type Params = $ptype; - type L = $ltype; - type N = $ntype; - - fn new(params: $ptype, x: $ntype) -> DSAPrivKey<$ptype> + pub fn new(params: $ptype, x: $ntype) -> DSAPrivateKey<$ptype> { - DSAPrivKey{ params, x } + DSAPrivateKey{ params, x } } - fn sign(&self, m: &[u8]) -> DSASignature<$ntype> + pub fn sign(&self, m: &[u8]) -> DSASignature<$ntype> where Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hmac: Mac @@ -155,7 +135,7 @@ macro_rules! generate_tests { let s = $nt::from_bytes(sbytes); let params = $params::new(p,g,q); - let private = DSAPrivKey::<$params>::new(params, x); + let private = DSAPrivateKey::<$params>::new(params, x); let sig = match h { 224 => private.sign::(mbytes), 256 => private.sign::(mbytes), diff --git a/src/dsa/public.rs b/src/dsa/public.rs index 8538d96..afcc418 100644 --- a/src/dsa/public.rs +++ b/src/dsa/public.rs @@ -7,45 +7,28 @@ use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,ToASN1}; use std::cmp::min; use utils::TranslateNums; -pub trait DSAPublicKey { - type Params : DSAParameters; - type L; - type N; - - /// Generate a new public key given the parameters and public value. - fn new(params: Self::Params, y: Self::L) -> Self; - /// Verify the given signature against the given message, using the - /// appropriate hash function. - fn verify(&self, m: &[u8], sig: &DSASignature) -> bool - where Hash: Digest; -} - -pub struct DSAPubKey { +pub struct DSAPublicKey { pub(crate) params: Params, pub(crate) y: Params::L } pub enum DSAPublic { - DSAPublicL1024N160(DSAPubKey), - DSAPublicL2048N224(DSAPubKey), - DSAPublicL2048N256(DSAPubKey), - DSAPublicL3072N256(DSAPubKey) + DSAPublicL1024N160(DSAPublicKey), + DSAPublicL2048N224(DSAPublicKey), + DSAPublicL2048N256(DSAPublicKey), + DSAPublicL3072N256(DSAPublicKey) } macro_rules! pubkey_impls { ($ptype: ident, $ltype: ident, $ntype: ident, $dbl: ident, $bdbl: ident) => { - impl DSAPublicKey for DSAPubKey<$ptype> + impl DSAPublicKey<$ptype> { - type Params = $ptype; - type L = $ltype; - type N = $ntype; - - fn new(params: $ptype, y: $ltype) -> DSAPubKey<$ptype> + pub fn new(params: $ptype, y: $ltype) -> DSAPublicKey<$ptype> { - DSAPubKey{ params, y } + DSAPublicKey{ params, y } } - fn verify(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool + pub fn verify(&self, m: &[u8], sig: &DSASignature<$ntype>) -> bool where Hash: Digest { if sig.r >= self.params.q { @@ -80,7 +63,7 @@ macro_rules! pubkey_impls { } } - impl ToASN1 for DSAPubKey<$ptype> { + impl ToASN1 for DSAPublicKey<$ptype> { type Error = ASN1EncodeErr; fn to_asn1_class(&self, c: ASN1Class) @@ -136,7 +119,7 @@ macro_rules! generate_tests { let s = $nt::from_bytes(sbytes); let params = $params::new(p,g,q); - let public = DSAPubKey::<$params>::new(params, y); + let public = DSAPublicKey::<$params>::new(params, y); let sig = DSASignature::<$nt>::new(r, s); match h { 224 => assert!(public.verify::(mbytes, &sig)), diff --git a/src/dsa/tests.rs b/src/dsa/tests.rs index f45fdb3..996aad2 100644 --- a/src/dsa/tests.rs +++ b/src/dsa/tests.rs @@ -4,8 +4,8 @@ use sha1::Sha1; use sha2::{Sha224,Sha256,Sha384,Sha512}; use simple_asn1::{der_decode,der_encode}; use dsa::params::{DSAParameters,L1024N160,L2048N256}; -use dsa::private::{DSAPrivateKey,DSAPrivKey}; -use dsa::public::{DSAPublicKey,DSAPubKey}; +use dsa::private::DSAPrivateKey; +use dsa::public::DSAPublicKey; use dsa::rfc6979::KIterator; macro_rules! run_rfc6979_test { @@ -99,8 +99,8 @@ fn appendix_a21() { let params = L1024N160::new(p, g, q); let x = U192::from_bytes(&xbytes); let y = U1024::from_bytes(&ybytes); - let private = DSAPrivKey::::new(params.clone(), x); - let public = DSAPubKey::::new(params.clone(), y); + let private = DSAPrivateKey::::new(params.clone(), x); + let public = DSAPublicKey::::new(params.clone(), y); // let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII @@ -359,8 +359,8 @@ fn appendix_a22() { let params = L2048N256::new(p, g, q); let x = U256::from_bytes(&xbytes); let y = U2048::from_bytes(&ybytes); - let private = DSAPrivKey::::new(params.clone(), x); - let public = DSAPubKey::::new(params.clone(), y); + let private = DSAPrivateKey::::new(params.clone(), x); + let public = DSAPublicKey::::new(params.clone(), y); // let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII diff --git a/src/ssh/dsa.rs b/src/ssh/dsa.rs index 12fd1a0..99ed967 100644 --- a/src/ssh/dsa.rs +++ b/src/ssh/dsa.rs @@ -1,5 +1,5 @@ use cryptonum::unsigned::*; -use dsa::{DSAKeyPair,DSAParameters,DSAPubKey,DSAPublicKey,DSAPrivKey,DSAPrivateKey,L1024N160}; +use dsa::{DSAKeyPair,DSAParameters,DSAPublicKey,DSAPrivateKey,L1024N160}; use std::io::{Read,Write}; use ssh::errors::{SSHKeyParseError,SSHKeyRenderError}; use ssh::frame::*; @@ -22,7 +22,7 @@ impl SSHKey for DSAKeyPair { let pubparams = L1024N160::new(pubp, pubg, pubq); let puby: U1024 = parse_openssh_number(inp)?; for _ in inp.bytes() { return Err(SSHKeyParseError::UnknownTrailingData); } - Ok(DSAPubKey::::new(pubparams.clone(), puby.clone())) + Ok(DSAPublicKey::::new(pubparams.clone(), puby.clone())) } fn parse_ssh_private_info(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError> @@ -43,7 +43,7 @@ impl SSHKey for DSAKeyPair { let _ = parse_openssh_buffer(inp)?; // a copy of y we don't need let privx = parse_openssh_number(inp)?; - let privkey = DSAPrivKey::::new(privparams, privx); + let privkey = DSAPrivateKey::::new(privparams, privx); let comment = parse_openssh_string(inp)?; for (idx,byte) in inp.bytes().enumerate() { if ((idx+1) as u8) != byte? { diff --git a/src/ssh/mod.rs b/src/ssh/mod.rs index 0606aef..aa77e74 100644 --- a/src/ssh/mod.rs +++ b/src/ssh/mod.rs @@ -142,7 +142,7 @@ pub fn write_ssh_keyfile(path: P, x: &KP, comment: &str) -> Result<(),SSHK #[cfg(test)] -use dsa::{DSAKeyPair,DSAPublicKey,DSAPrivateKey,DSAPubKey,L1024N160}; +use dsa::{DSAKeyPair,DSAPublicKey,L1024N160}; #[cfg(test)] use sha2::Sha256; @@ -183,7 +183,7 @@ fn read_dsa_examples() { match load_ssh_pubkeys::,String>(ppath) { Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)), Ok(pubkeys) => { - let _ : Vec<(DSAPubKey,String)> = pubkeys; + let _ : Vec<(DSAPublicKey,String)> = pubkeys; for (pubkey, comment3) in pubkeys { assert_eq!(pubkey.params.p, keypair.public.params.p, "public key check (p)"); assert_eq!(pubkey.params.q, keypair.public.params.q, "public key check (q)"); diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 5a0580e..978d51d 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -6,7 +6,7 @@ mod name; mod publickey; mod validity; -use dsa::{DSAPublic,DSAPublicKey}; +use dsa::DSAPublic; use ecdsa::{ECDSAPublic,ECCPublicKey}; use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512}; use sha1::Sha1; diff --git a/src/x509/publickey.rs b/src/x509/publickey.rs index e821111..bc12cbd 100644 --- a/src/x509/publickey.rs +++ b/src/x509/publickey.rs @@ -1,5 +1,5 @@ use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192}; -use dsa::{DSAPublic,DSAPublicKey,DSAPubKey,DSAParameters}; +use dsa::{DSAPublic,DSAPublicKey,DSAParameters}; use dsa::{L3072N256,L2048N256,L2048N224,L1024N160}; use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPubKey}; use ecdsa::curve::{P192,P224,P256,P384,P521}; @@ -174,7 +174,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result::new(params, y); + let key = DSAPublicKey::::new(params, y); let reskey = DSAPublic::DSAPublicL3072N256(key); return Ok(reskey); } @@ -195,7 +195,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result::new(params, y); + let key = DSAPublicKey::::new(params, y); let reskey = DSAPublic::DSAPublicL2048N256(key); return Ok(reskey); } @@ -213,7 +213,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result::new(params, y); + let key = DSAPublicKey::::new(params, y); let reskey = DSAPublic::DSAPublicL2048N224(key); return Ok(reskey); } @@ -233,7 +233,7 @@ fn decode_dsa_key(info: ASN1Block, key: &ASN1Block) -> Result::new(params, y); + let key = DSAPublicKey::::new(params, y); let reskey = DSAPublic::DSAPublicL1024N160(key); return Ok(reskey); } From 40a57930891f2259b037a93f18c2e873dc3a431b Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sat, 13 Apr 2019 16:41:41 -0700 Subject: [PATCH 2/5] Clean up the struct/trait split for RSA keys. --- src/rsa/core.rs | 14 +++ src/rsa/mod.rs | 74 +++++++--------- src/rsa/private.rs | 106 +++++++++------------- src/rsa/public.rs | 216 +++++++++++++++++++++------------------------ 4 files changed, 191 insertions(+), 219 deletions(-) diff --git a/src/rsa/core.rs b/src/rsa/core.rs index ba73800..fe98d04 100644 --- a/src/rsa/core.rs +++ b/src/rsa/core.rs @@ -1,7 +1,21 @@ +use cryptonum::unsigned::*; use num::bigint::BigUint; use rsa::errors::RSAError; use simple_asn1::{ASN1Block,ASN1DecodeErr}; +pub trait RSAMode { + type Barrett; +} + +impl RSAMode for U512 { type Barrett = BarrettU512; } +impl RSAMode for U1024 { type Barrett = BarrettU1024; } +impl RSAMode for U2048 { type Barrett = BarrettU2048; } +impl RSAMode for U3072 { type Barrett = BarrettU3072; } +impl RSAMode for U4096 { type Barrett = BarrettU4096; } +impl RSAMode for U8192 { type Barrett = BarrettU8192; } +impl RSAMode for U15360 { type Barrett = BarrettU15360; } + + pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec { let mut idhash = Vec::new(); diff --git a/src/rsa/mod.rs b/src/rsa/mod.rs index 7b0bd6b..0221111 100644 --- a/src/rsa/mod.rs +++ b/src/rsa/mod.rs @@ -24,6 +24,7 @@ mod private; mod public; mod signing_hashes; +pub use self::core::RSAMode; pub use self::errors::RSAError; pub use self::signing_hashes::{SigningHash, SIGNING_HASH_NULL, @@ -33,15 +34,8 @@ pub use self::signing_hashes::{SigningHash, SIGNING_HASH_SHA384, SIGNING_HASH_SHA512}; pub use self::oaep::OAEPParams; -pub use self::private::{RSAPrivate, RSAPrivateKey, - RSA512Private, RSA1024Private, RSA2048Private, - RSA3072Private, RSA4096Private, RSA8192Private, - RSA15360Private}; -pub use self::public::{RSAPublic, RSAPublicKey, - RSA512Public, RSA1024Public, RSA2048Public, - RSA3072Public, RSA4096Public, RSA8192Public, - RSA15360Public}; - +pub use self::private::{RSAPrivate, RSAPrivateKey}; +pub use self::public::{RSAPublic, RSAPublicKey}; use cryptonum::signed::{EGCD,ModInv}; use cryptonum::unsigned::{CryptoNum,PrimeGen}; use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360}; @@ -60,38 +54,38 @@ fn diff(a: &T, b: &T) -> T } } +pub struct RSAKeyPair { + pub public: RSAPublicKey, + pub private: RSAPrivateKey +} + macro_rules! generate_rsa_pair { - ($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident, $iterations: expr) => { - pub struct $pair { - pub public: $pub, - pub private: $priv - } - - impl $pair { - pub fn new(pu: $pub, pr: $priv) -> $pair { - $pair { + ($uint: ident, $half: ident, $iterations: expr) => { + impl RSAKeyPair<$uint> { + pub fn new(pu: RSAPublicKey<$uint>, pr: RSAPrivateKey<$uint>) -> RSAKeyPair<$uint> { + RSAKeyPair { public: pu, private: pr } } - pub fn generate(rng: &mut G) -> $pair + pub fn generate(rng: &mut G) -> RSAKeyPair<$uint> where G: RngCore { loop { let ebase = 65537u32; let e = $uint::from(ebase); - let (p, q) = $pair::generate_pq(rng, &$half::from(ebase)); + let (p, q) = RSAKeyPair::<$uint>::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); - let private = $priv::new(n, d); - return $pair::new(public, private); + let public = RSAPublicKey::<$uint>::new(n.clone(), e); + let private = RSAPrivateKey::<$uint>::new(n, d); + return RSAKeyPair::<$uint>::new(public, private); } } } @@ -129,13 +123,13 @@ macro_rules! generate_rsa_pair } } -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); +generate_rsa_pair!(U512, U256, 7); +generate_rsa_pair!(U1024, U512, 7); +generate_rsa_pair!(U2048, U1024, 4); +generate_rsa_pair!(U3072, U1536, 3); +generate_rsa_pair!(U4096, U2048, 3); +generate_rsa_pair!(U8192, U4096, 3); +generate_rsa_pair!(U15360, U7680, 3); #[cfg(test)] mod generation { @@ -143,15 +137,15 @@ mod generation { use std::fmt; use super::*; - impl Clone for RSA512KeyPair { - fn clone(&self) -> RSA512KeyPair { - RSA512KeyPair{ - public: RSA512Public { + impl Clone for RSAKeyPair { + fn clone(&self) -> RSAKeyPair { + RSAKeyPair { + public: RSAPublicKey { n: self.public.n.clone(), nu: self.public.nu.clone(), e: self.public.e.clone(), }, - private: RSA512Private { + private: RSAPrivateKey { nu: self.private.nu.clone(), d: self.private.d.clone() } @@ -159,7 +153,7 @@ mod generation { } } - impl fmt::Debug for RSA512KeyPair { + impl fmt::Debug for RSAKeyPair { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("RSA512KeyPair") .field("n", &self.public.n) @@ -169,14 +163,14 @@ mod generation { } } - impl Arbitrary for RSA512KeyPair { - fn arbitrary(g: &mut G) -> RSA512KeyPair { - RSA512KeyPair::generate(g) + impl Arbitrary for RSAKeyPair { + fn arbitrary(g: &mut G) -> RSAKeyPair { + RSAKeyPair::::generate(g) } } quickcheck! { - fn generate_and_sign(keypair: RSA512KeyPair, msg: Vec) -> bool { + fn generate_and_sign(keypair: RSAKeyPair, msg: Vec) -> bool { let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg); keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig) } diff --git a/src/rsa/private.rs b/src/rsa/private.rs index aa139cf..57dcd75 100644 --- a/src/rsa/private.rs +++ b/src/rsa/private.rs @@ -1,56 +1,36 @@ use cryptonum::unsigned::*; use digest::{Digest,FixedOutput}; -use rsa::core::{drop0s,pkcs1_pad,xor_vecs}; +use rsa::core::{RSAMode,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 struct RSAPrivateKey +{ + pub(crate) nu: R::Barrett, + pub(crate) d: R } pub enum RSAPrivate { - Key512(RSA512Private), - Key1024(RSA1024Private), - Key2048(RSA2048Private), - Key3072(RSA3072Private), - Key4096(RSA4096Private), - Key8192(RSA8192Private), - Key15360(RSA15360Private) + Key512(RSAPrivateKey), + Key1024(RSAPrivateKey), + Key2048(RSAPrivateKey), + Key3072(RSAPrivateKey), + Key4096(RSAPrivateKey), + Key8192(RSAPrivateKey), + Key15360(RSAPrivateKey) } 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 { + ($num: ident, $bar: ident, $size: expr) => { + impl RSAPrivateKey<$num> { + pub fn new(n: $num, d: $num) -> RSAPrivateKey<$num> { let nu = $bar::new(n.clone()); - $rsa { nu: nu, d: d } + RSAPrivateKey{ nu: nu, d: d } } - fn sign(&self, signhash: &SigningHash, msg: &[u8]) + pub fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec { let hash = (signhash.run)(msg); @@ -61,7 +41,7 @@ macro_rules! generate_rsa_private sig } - fn decrypt(&self, oaep: &OAEPParams, msg: &[u8]) + pub fn decrypt(&self, oaep: &OAEPParams, msg: &[u8]) -> Result,RSAError> where H: Default + Digest + FixedOutput { @@ -74,9 +54,7 @@ macro_rules! generate_rsa_private Ok(res) } - } - impl $rsa { fn sp1(&self, m: &$num) -> $num { m.modexp(&self.d, &self.nu) } @@ -139,17 +117,17 @@ macro_rules! generate_rsa_private } } -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); +generate_rsa_private!(U512, BarrettU512, 512); +generate_rsa_private!(U1024, BarrettU1024, 1024); +generate_rsa_private!(U2048, BarrettU2048, 2048); +generate_rsa_private!(U3072, BarrettU3072, 3072); +generate_rsa_private!(U4096, BarrettU4096, 4096); +generate_rsa_private!(U8192, BarrettU8192, 8192); +generate_rsa_private!(U15360, BarrettU15360, 15360); #[cfg(test)] macro_rules! sign_test_body { - ($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { let fname = format!("testdata/rsa/sign{}.test", $size); run_test(fname.to_string(), 7, |case| { let (neg0, dbytes) = case.get("d").unwrap(); @@ -173,7 +151,7 @@ macro_rules! sign_test_body { 512 => &SIGNING_HASH_SHA512, x => panic!("Bad signing hash: {}", x) }; - let privkey = $rsa{ nu: $bar::from_components(k, n.clone(), nu), d: d }; + let privkey = RSAPrivateKey{ nu: $bar::from_components(k, n.clone(), nu), d: d }; let sig = privkey.sign(sighash, &mbytes); assert_eq!(*sbytes, sig); }); @@ -182,7 +160,7 @@ macro_rules! sign_test_body { #[cfg(test)] macro_rules! decrypt_test_body { - ($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { let fname = format!("testdata/rsa/encrypt{}.test", $size); run_test(fname.to_string(), 9, |case| { let (neg0, nbytes) = case.get("n").unwrap(); @@ -203,7 +181,7 @@ macro_rules! decrypt_test_body { let k = usize::from(bigk); let d = $num::from_bytes(dbytes); let nu = $bar::from_components(k, n64, nu); - let privkey = $rsa{ nu: nu, d: d }; + let privkey = RSAPrivateKey{ nu: nu, d: d }; let lstr = String::from_utf8(lbytes.clone()).unwrap(); let message = match usize::from($num::from_bytes(hbytes)) { 224 => privkey.decrypt(&OAEPParams::::new(lstr), &cbytes), @@ -219,7 +197,7 @@ macro_rules! decrypt_test_body { } macro_rules! generate_tests { - ($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { #[cfg(test)] #[allow(non_snake_case)] mod $mod { @@ -231,16 +209,16 @@ macro_rules! generate_tests { #[test] fn sign() { - sign_test_body!($mod, $rsa, $num, $bar, $num64, $size); + sign_test_body!($mod, $num, $bar, $num64, $size); } #[test] fn decrypt() { - decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size); + decrypt_test_body!($mod, $num, $bar, $num64, $size); } } }; - (ignore $mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + (ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { #[cfg(test)] #[allow(non_snake_case)] mod $mod { @@ -253,22 +231,22 @@ macro_rules! generate_tests { #[ignore] #[test] fn sign() { - sign_test_body!($mod, $rsa, $num, $bar, $num64, $size); + sign_test_body!($mod, $num, $bar, $num64, $size); } #[ignore] #[test] fn decrypt() { - decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size); + decrypt_test_body!($mod, $num, $bar, $num64, $size); } } } } -generate_tests!(RSA512, RSA512Private, U512, BarrettU512, U576, 512); -generate_tests!(RSA1024, RSA1024Private, U1024, BarrettU1024, U1088, 1024); -generate_tests!(RSA2048, RSA2048Private, U2048, BarrettU2048, U2112, 2048); -generate_tests!(RSA3072, RSA3072Private, U3072, BarrettU3072, U3136, 3072); -generate_tests!(RSA4096, RSA4096Private, U4096, BarrettU4096, U4160, 4096); -generate_tests!(ignore RSA8192, RSA8192Private, U8192, BarrettU8192, U8256, 8192); -generate_tests!(ignore RSA15360, RSA15360Private, U15360, BarrettU15360, U15424, 15360); \ No newline at end of file +generate_tests!( RSA512, U512, BarrettU512, U576, 512); +generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024); +generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048); +generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072); +generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096); +generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192); +generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360); \ No newline at end of file diff --git a/src/rsa/public.rs b/src/rsa/public.rs index 4b628d5..528fd01 100644 --- a/src/rsa/public.rs +++ b/src/rsa/public.rs @@ -2,7 +2,7 @@ use cryptonum::unsigned::*; use digest::{Digest,FixedOutput}; use rand::Rng; use rand::rngs::OsRng; -use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs}; +use rsa::core::{RSAMode,decode_biguint,pkcs1_pad,xor_vecs}; use rsa::errors::RSAError; use rsa::oaep::OAEPParams; use rsa::signing_hashes::SigningHash; @@ -12,62 +12,21 @@ use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr, use std::fmt; use utils::TranslateNums; -pub trait RSAPublicKey { - /// Generate a new public key pair for the given modulus and - /// exponent. You should probably not call this directly unless - /// you're writing a key generation function or writing your own - /// public key parser. - fn new(n: N, e: N) -> Self; - - /// Verify that the provided signature is valid; that the private - /// key associated with this public key sent exactly this message. - /// The hash used here must exactly match the hash used to sign - /// the message, including its ASN.1 metadata. - fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool; - - /// Encrypt the message with a hash function, given the appropriate - /// label. Please note that RSA encryption is not particularly fast, - /// and decryption is very slow indeed. Thus, most crypto systems that - /// need asymmetric encryption should generate a symmetric key, encrypt - /// that key with RSA encryption, and then encrypt the actual message - /// with that symmetric key. - /// - /// In this variant of the function, we use an explicit random number - /// generator, just in case you have one you really like. It better be - /// cryptographically strong, though, as some of the padding protections - /// are relying on it. - fn encrypt_rng(&self, g: &mut G, oaep: &OAEPParams, msg: &[u8]) - -> Result,RSAError> - where - G: Rng, - H: Default + Digest + FixedOutput; - - /// Encrypt the message with a hash function, given the appropriate - /// label. Please note that RSA encryption is not particularly fast, - /// and decryption is very slow indeed. Thus, most crypto systems that - /// need asymmetric encryption should generate a symmetric key, encrypt - /// that key with RSA encryption, and then encrypt the actual message - /// with that symmetric key. - /// - /// This variant will just use the system RNG for its randomness. - fn encrypt(&self,oaep:&OAEPParams,msg:&[u8]) - -> Result,RSAError> - where - H: Default + Digest + FixedOutput - { - let mut g = OsRng::new()?; - self.encrypt_rng(&mut g, oaep, msg) - } +#[derive(PartialEq)] +pub struct RSAPublicKey { + pub(crate) n: R, + pub(crate) nu: R::Barrett, + pub(crate) e: R } pub enum RSAPublic { - Key512(RSA512Public), - Key1024(RSA1024Public), - Key2048(RSA2048Public), - Key3072(RSA3072Public), - Key4096(RSA4096Public), - Key8192(RSA8192Public), - Key15360(RSA15360Public) + Key512( RSAPublicKey), + Key1024( RSAPublicKey), + Key2048( RSAPublicKey), + Key3072( RSAPublicKey), + Key4096( RSAPublicKey), + Key8192( RSAPublicKey), + Key15360(RSAPublicKey) } impl RSAPublic { @@ -109,43 +68,43 @@ impl FromASN1 for RSAPublic { 512 => { let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?; let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?; - let res = RSA512Public::new(n2, e2); + let res = RSAPublicKey::::new(n2, e2); Ok((RSAPublic::Key512(res), rest)) } 1024 => { let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?; let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?; - let res = RSA1024Public::new(n2, e2); + let res = RSAPublicKey::::new(n2, e2); Ok((RSAPublic::Key1024(res), rest)) } 2048 => { let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?; let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?; - let res = RSA2048Public::new(n2, e2); + let res = RSAPublicKey::::new(n2, e2); Ok((RSAPublic::Key2048(res), rest)) } 3072 => { let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?; let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?; - let res = RSA3072Public::new(n2, e2); + let res = RSAPublicKey::::new(n2, e2); Ok((RSAPublic::Key3072(res), rest)) } 4096 => { let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?; let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?; - let res = RSA4096Public::new(n2, e2); + let res = RSAPublicKey::::new(n2, e2); Ok((RSAPublic::Key4096(res), rest)) } 8192 => { let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?; let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?; - let res = RSA8192Public::new(n2, e2); + let res = RSAPublicKey::::new(n2, e2); Ok((RSAPublic::Key8192(res), rest)) } 15360 => { let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?; let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?; - let res = RSA15360Public::new(n2, e2); + let res = RSAPublicKey::::new(n2, e2); Ok((RSAPublic::Key15360(res), rest)) } _ => @@ -178,21 +137,22 @@ impl ToASN1 for RSAPublic { macro_rules! generate_rsa_public { - ($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => { - #[derive(PartialEq)] - pub struct $rsa { - pub(crate) n: $num, - pub(crate) nu: $bar, - pub(crate) e: $num - } - - impl RSAPublicKey<$num> for $rsa { - fn new(n: $num, e: $num) -> $rsa { + ($num: ident, $bar: ident, $var: ident, $size: expr) => { + impl RSAPublicKey<$num> { + /// Generate a new public key pair for the given modulus and + /// exponent. You should probably not call this directly unless + /// you're writing a key generation function or writing your own + /// public key parser. + pub fn new(n: $num, e: $num) -> RSAPublicKey<$num> { let nu = $bar::new(n.clone()); - $rsa { n: n, nu: nu, e: e } + RSAPublicKey{ n: n, nu: nu, e: e } } - fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) + /// Verify that the provided signature is valid; that the private + /// key associated with this public key sent exactly this message. + /// The hash used here must exactly match the hash used to sign + /// the message, including its ASN.1 metadata. + pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool { let hash: Vec = (signhash.run)(msg); @@ -203,7 +163,18 @@ macro_rules! generate_rsa_public em == em_ } - fn encrypt_rng(&self,g: &mut G,oaep: &OAEPParams,msg: &[u8]) + /// Encrypt the message with a hash function, given the appropriate + /// label. Please note that RSA encryption is not particularly fast, + /// and decryption is very slow indeed. Thus, most crypto systems that + /// need asymmetric encryption should generate a symmetric key, encrypt + /// that key with RSA encryption, and then encrypt the actual message + /// with that symmetric key. + /// + /// In this variant of the function, we use an explicit random number + /// generator, just in case you have one you really like. It better be + /// cryptographically strong, though, as some of the padding protections + /// are relying on it. + pub fn encrypt_rng(&self,g: &mut G,oaep: &OAEPParams,msg: &[u8]) -> Result,RSAError> where G: Rng, @@ -222,9 +193,24 @@ macro_rules! generate_rsa_public Ok(res) } - } - impl $rsa { + /// Encrypt the message with a hash function, given the appropriate + /// label. Please note that RSA encryption is not particularly fast, + /// and decryption is very slow indeed. Thus, most crypto systems that + /// need asymmetric encryption should generate a symmetric key, encrypt + /// that key with RSA encryption, and then encrypt the actual message + /// with that symmetric key. + /// + /// This variant will just use the system RNG for its randomness. + pub fn encrypt(&self,oaep:&OAEPParams,msg:&[u8]) + -> Result,RSAError> + where + H: Default + Digest + FixedOutput + { + let mut g = OsRng::new()?; + self.encrypt_rng(&mut g, oaep, msg) + } + fn vp1(&self, s: &$num) -> $num { s.modexp(&self.e, &self.nu) } @@ -283,11 +269,11 @@ macro_rules! generate_rsa_public } } - impl FromASN1 for $rsa { + impl FromASN1 for RSAPublicKey<$num> { type Error = RSAError; fn from_asn1(bs: &[ASN1Block]) - -> Result<($rsa,&[ASN1Block]),RSAError> + -> Result<(RSAPublicKey<$num>,&[ASN1Block]),RSAError> { let (core, rest) = RSAPublic::from_asn1(bs)?; @@ -298,7 +284,7 @@ macro_rules! generate_rsa_public } } - impl ToASN1 for $rsa { + impl ToASN1 for RSAPublicKey<$num> { type Error = ASN1EncodeErr; fn to_asn1_class(&self, c: ASN1Class) @@ -314,7 +300,7 @@ macro_rules! generate_rsa_public } #[cfg(test)] - impl fmt::Debug for $rsa { + impl fmt::Debug for RSAPublicKey<$num> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct(stringify!($rsa)) .field("n", &self.n) @@ -326,17 +312,17 @@ macro_rules! generate_rsa_public } } -generate_rsa_public!(RSA512Public, U512, BarrettU512, Key512, 512); -generate_rsa_public!(RSA1024Public, U1024, BarrettU1024, Key1024, 1024); -generate_rsa_public!(RSA2048Public, U2048, BarrettU2048, Key2048, 2048); -generate_rsa_public!(RSA3072Public, U3072, BarrettU3072, Key3072, 3072); -generate_rsa_public!(RSA4096Public, U4096, BarrettU4096, Key4096, 4096); -generate_rsa_public!(RSA8192Public, U8192, BarrettU8192, Key8192, 8192); -generate_rsa_public!(RSA15360Public, U15360, BarrettU15360, Key15360, 15360); +generate_rsa_public!(U512, BarrettU512, Key512, 512); +generate_rsa_public!(U1024, BarrettU1024, Key1024, 1024); +generate_rsa_public!(U2048, BarrettU2048, Key2048, 2048); +generate_rsa_public!(U3072, BarrettU3072, Key3072, 3072); +generate_rsa_public!(U4096, BarrettU4096, Key4096, 4096); +generate_rsa_public!(U8192, BarrettU8192, Key8192, 8192); +generate_rsa_public!(U15360, BarrettU15360, Key15360, 15360); #[cfg(test)] macro_rules! new_test_body { - ($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { let fname = format!("testdata/rsa/sign{}.test", $size); run_test(fname.to_string(), 7, |case| { let (neg0, nbytes) = case.get("n").unwrap(); @@ -350,8 +336,8 @@ macro_rules! new_test_body { let bigk = $num::from_bytes(kbytes); let k = usize::from(bigk); let e = $num::from(65537u64); - let pubkey2 = $rsa::new(n.clone(), e.clone()); - let pubkey1 = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; + let pubkey2 = RSAPublicKey::<$num>::new(n.clone(), e.clone()); + let pubkey1 = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; assert_eq!(pubkey1, pubkey2); }); }; @@ -359,7 +345,7 @@ macro_rules! new_test_body { #[cfg(test)] macro_rules! encode_test_body { - ($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { let fname = format!("testdata/rsa/sign{}.test", $size); run_test(fname.to_string(), 7, |case| { let (neg0, nbytes) = case.get("n").unwrap(); @@ -373,9 +359,9 @@ macro_rules! encode_test_body { let bigk = $num::from_bytes(kbytes); let k = usize::from(bigk); let e = $num::from(65537u64); - let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; + let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; let asn1 = pubkey.to_asn1().unwrap(); - let (pubkey2, _) = $rsa::from_asn1(&asn1).unwrap(); + let (pubkey2, _) = RSAPublicKey::from_asn1(&asn1).unwrap(); assert_eq!(pubkey, pubkey2); }); }; @@ -383,7 +369,7 @@ macro_rules! encode_test_body { #[cfg(test)] macro_rules! verify_test_body { - ($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { let fname = format!("testdata/rsa/sign{}.test", $size); run_test(fname.to_string(), 7, |case| { let (neg0, nbytes) = case.get("n").unwrap(); @@ -400,7 +386,7 @@ macro_rules! verify_test_body { let bigk = $num::from_bytes(kbytes); let k = usize::from(bigk); let e = $num::from(65537u64); - let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; + let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; let hashnum = u64::from($num::from_bytes(hbytes)); let sighash = match hashnum { 160 => &SIGNING_HASH_SHA1, @@ -417,7 +403,7 @@ macro_rules! verify_test_body { #[cfg(test)] macro_rules! encrypt_test_body { - ($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { let fname = format!("testdata/rsa/encrypt{}.test", $size); run_test(fname.to_string(), 9, |case| { let (neg0, nbytes) = case.get("n").unwrap(); @@ -438,8 +424,8 @@ macro_rules! encrypt_test_body { let e = $num::from(65537u64); let d = $num::from_bytes(dbytes); let nu = $bar::from_components(k, n64, nu); - let pubkey = $rsa{ n: n.clone(), nu: nu.clone(), e: e }; - let privkey = $priv{ nu: nu, d: d }; + let pubkey = RSAPublicKey{ n: n.clone(), nu: nu.clone(), e: e }; + let privkey = RSAPrivateKey{ nu: nu, d: d }; let lstr = String::from_utf8(lbytes.clone()).unwrap(); let cipher = match usize::from($num::from_bytes(hbytes)) { 224 => pubkey.encrypt(&OAEPParams::::new(lstr.clone()), mbytes), @@ -463,7 +449,7 @@ macro_rules! encrypt_test_body { } macro_rules! generate_tests { - ($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { #[cfg(test)] #[allow(non_snake_case)] mod $mod { @@ -475,16 +461,16 @@ macro_rules! generate_tests { use sha2::{Sha224,Sha256,Sha384,Sha512}; #[test] - fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn new() { new_test_body!($mod, $num, $bar, $num64, $size); } #[test] - fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); } #[test] - fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); } #[test] - fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); } } }; - (ignore $mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { + (ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { #[cfg(test)] #[allow(non_snake_case)] mod $mod { @@ -497,24 +483,24 @@ macro_rules! generate_tests { #[ignore] #[test] - fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn new() { new_test_body!($mod, $num, $bar, $num64, $size); } #[ignore] #[test] - fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); } #[ignore] #[test] - fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); } #[ignore] #[test] - fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } + fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); } } }; } -generate_tests!(RSA512, RSA512Public, RSA512Private, U512, BarrettU512, U576, 512); -generate_tests!(RSA1024, RSA1024Public, RSA1024Private, U1024, BarrettU1024, U1088, 1024); -generate_tests!(RSA2048, RSA2048Public, RSA2048Private, U2048, BarrettU2048, U2112, 2048); -generate_tests!(RSA3072, RSA3072Public, RSA3072Private, U3072, BarrettU3072, U3136, 3072); -generate_tests!(RSA4096, RSA4096Public, RSA4096Private, U4096, BarrettU4096, U4160, 4096); -generate_tests!(ignore RSA8192, RSA8192Public, RSA8192Private, U8192, BarrettU8192, U8256, 8192); -generate_tests!(ignore RSA15360, RSA15360Public, RSA15360Private, U15360, BarrettU15360, U15424, 15360); \ No newline at end of file +generate_tests!( RSA512, U512, BarrettU512, U576, 512); +generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024); +generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048); +generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072); +generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096); +generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192); +generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360); \ No newline at end of file From cfc06c3b5640820ac32027e7925d5da9e309878f Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sat, 13 Apr 2019 16:51:25 -0700 Subject: [PATCH 3/5] Simplify ECDSA struct/trait split. --- src/ecdsa/mod.rs | 20 +++++++++++--------- src/ecdsa/private.rs | 24 ++++++----------------- src/ecdsa/public.rs | 44 +++++++++++++++---------------------------- src/x509/mod.rs | 2 +- src/x509/publickey.rs | 12 ++++++------ 5 files changed, 39 insertions(+), 63 deletions(-) diff --git a/src/ecdsa/mod.rs b/src/ecdsa/mod.rs index 2f28388..e10c580 100644 --- a/src/ecdsa/mod.rs +++ b/src/ecdsa/mod.rs @@ -10,18 +10,19 @@ use rand::Rng; use rand::distributions::Standard; use self::curve::{EllipticCurve,P192,P224,P256,P384,P521}; use self::point::{ECCPoint,Point}; -pub use self::private::{ECCPrivateKey,ECCPrivate}; -pub use self::public::{ECCPublicKey,ECDSAPublic,ECCPubKey}; +pub use self::private::ECCPrivateKey; +pub use self::public::{ECDSAPublic,ECCPublicKey}; pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr}; -pub trait ECDSAKeyPair { - fn generate(g: &mut G) -> (Public, Private); +pub struct ECDSAKeyPair { + pub public: ECCPublicKey, + pub private: ECCPrivateKey } macro_rules! generate_impl { ($curve: ident, $un: ident, $si: ident) => { - impl ECDSAKeyPair,ECCPrivate<$curve>> for $curve { - fn generate(rng: &mut G) -> (ECCPubKey<$curve>, ECCPrivate<$curve>) + impl ECDSAKeyPair<$curve> { + pub fn generate(rng: &mut G) -> ECDSAKeyPair<$curve> { loop { let size = ($curve::size() + 7) / 8; @@ -38,9 +39,10 @@ macro_rules! generate_impl { let d = $si::from(&proposed_d); let public_point = Point::<$curve>::default().scale(&d); - let public = ECCPubKey::<$curve>::new(public_point); - let private = ECCPrivate::<$curve>::new(proposed_d); - return (public, private); + let public = ECCPublicKey::<$curve>::new(public_point); + let private = ECCPrivateKey::<$curve>::new(proposed_d); + + return ECDSAKeyPair{ public, private }; } } } diff --git a/src/ecdsa/private.rs b/src/ecdsa/private.rs index 6aeb471..47c1059 100644 --- a/src/ecdsa/private.rs +++ b/src/ecdsa/private.rs @@ -6,33 +6,21 @@ use ecdsa::curve::{EllipticCurve,P192,P224,P256,P384,P521}; use ecdsa::point::{ECCPoint,Point}; use hmac::{Hmac,Mac}; -pub struct ECCPrivate { +pub struct ECCPrivateKey { d: Curve::Unsigned } -pub trait ECCPrivateKey { - type Unsigned; - - fn new(d: Self::Unsigned) -> Self; - fn sign(&self, m: &[u8]) -> DSASignature - where - Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, - Hmac: Mac; -} - macro_rules! generate_privates { ($curve: ident, $base: ident, $sig: ident, $dbl: ident, $quad: ident) => { - impl ECCPrivateKey for ECCPrivate<$curve> + impl ECCPrivateKey<$curve> { - type Unsigned = $base; - - fn new(d: $base) -> ECCPrivate<$curve> + pub fn new(d: $base) -> ECCPrivateKey<$curve> { - ECCPrivate{ d } + ECCPrivateKey{ d } } - fn sign(&self, m: &[u8]) -> DSASignature<$base> + pub fn sign(&self, m: &[u8]) -> DSASignature<$base> where Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hmac: Mac @@ -136,7 +124,7 @@ macro_rules! sign_test_body let r = $base::from_bytes(rbytes); let s = $base::from_bytes(sbytes); - let private = ECCPrivate::<$curve>::new(d); + let private = ECCPrivateKey::<$curve>::new(d); let sig = match usize::from(h) { 224 => private.sign::(mbytes), 256 => private.sign::(mbytes), diff --git a/src/ecdsa/public.rs b/src/ecdsa/public.rs index cdf6595..957b0e7 100644 --- a/src/ecdsa/public.rs +++ b/src/ecdsa/public.rs @@ -8,27 +8,16 @@ use hmac::{Hmac,Mac}; use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,FromASN1,ToASN1}; use std::cmp::min; -pub struct ECCPubKey { +pub struct ECCPublicKey { q: Point } pub enum ECDSAPublic { - ECCPublicP192(ECCPubKey), - ECCPublicP224(ECCPubKey), - ECCPublicP256(ECCPubKey), - ECCPublicP384(ECCPubKey), - ECCPublicP521(ECCPubKey), -} - -pub trait ECCPublicKey { - type Curve : EllipticCurve; - type Unsigned; - - fn new(d: Point) -> Self; - fn verify(&self, m: &[u8], sig: &DSASignature) -> bool - where - Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, - Hmac: Mac; + ECCPublicP192(ECCPublicKey), + ECCPublicP224(ECCPublicKey), + ECCPublicP256(ECCPublicKey), + ECCPublicP384(ECCPublicKey), + ECCPublicP521(ECCPublicKey), } pub enum ECDSAEncodeErr { @@ -58,17 +47,14 @@ impl From for ECDSADecodeErr { macro_rules! public_impl { ($curve: ident, $un: ident, $si: ident) => { - impl ECCPublicKey for ECCPubKey<$curve> + impl ECCPublicKey<$curve> { - type Curve = $curve; - type Unsigned = $un; - - fn new(q: Point<$curve>) -> ECCPubKey<$curve> + pub fn new(q: Point<$curve>) -> ECCPublicKey<$curve> { - ECCPubKey{ q } + ECCPublicKey{ q } } - fn verify(&self, m: &[u8], sig: &DSASignature) -> bool + pub fn verify(&self, m: &[u8], sig: &DSASignature<$un>) -> bool where Hash: BlockInput + Clone + Default + Digest + FixedOutput + Input + Reset, Hmac: Mac @@ -103,7 +89,7 @@ macro_rules! public_impl { } } - impl ToASN1 for ECCPubKey<$curve> { + impl ToASN1 for ECCPublicKey<$curve> { type Error = ECDSAEncodeErr; fn to_asn1_class(&self, c: ASN1Class) -> Result,ECDSAEncodeErr> @@ -136,10 +122,10 @@ macro_rules! public_impl { } } - impl FromASN1 for ECCPubKey<$curve> { + impl FromASN1 for ECCPublicKey<$curve> { type Error = ECDSADecodeErr; - fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPubKey<$curve>,&[ASN1Block]),ECDSADecodeErr> + fn from_asn1(bs: &[ASN1Block]) -> Result<(ECCPublicKey<$curve>,&[ASN1Block]),ECDSADecodeErr> { let (x, rest) = bs.split_first().ok_or(ECDSADecodeErr::NoKeyFound)?; if let ASN1Block::BitString(_, _, _, target) = x { @@ -155,7 +141,7 @@ macro_rules! public_impl { let x = $un::from_bytes(xbstr); let y = $un::from_bytes(ybstr); let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) }; - let res = ECCPubKey::<$curve>::new(point); + let res = ECCPublicKey::<$curve>::new(point); Ok((res, rest)) } else { Err(ECDSADecodeErr::InvalidKeyFormat) @@ -201,7 +187,7 @@ macro_rules! verify_test_body let s = $un::from_bytes(sbytes); let point = Point::<$curve>{ x: $si::from(x), y: $si::from(y) }; - let public = ECCPubKey::<$curve>::new(point); + let public = ECCPublicKey::<$curve>::new(point); let sig = DSASignature::new(r, s); match usize::from(h) { 224 => assert!(public.verify::(mbytes, &sig)), diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 978d51d..ccfc6ee 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -7,7 +7,7 @@ mod publickey; mod validity; use dsa::DSAPublic; -use ecdsa::{ECDSAPublic,ECCPublicKey}; +use ecdsa::ECDSAPublic; use rsa::{SIGNING_HASH_SHA1,SIGNING_HASH_SHA224,SIGNING_HASH_SHA256,SIGNING_HASH_SHA384,SIGNING_HASH_SHA512}; use sha1::Sha1; use sha2::{Sha224,Sha256,Sha384,Sha512}; diff --git a/src/x509/publickey.rs b/src/x509/publickey.rs index bc12cbd..da5ff07 100644 --- a/src/x509/publickey.rs +++ b/src/x509/publickey.rs @@ -1,7 +1,7 @@ use cryptonum::unsigned::{U3072,U2048,U1024,U256,U192}; use dsa::{DSAPublic,DSAPublicKey,DSAParameters}; use dsa::{L3072N256,L2048N256,L2048N224,L1024N160}; -use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPubKey}; +use ecdsa::{ECDSAEncodeErr,ECDSAPublic,ECCPublicKey}; use ecdsa::curve::{P192,P224,P256,P384,P521}; use num::BigUint; use rsa::RSAPublic; @@ -271,27 +271,27 @@ fn decode_ecdsa_key(info: ASN1Block, keybls: &[ASN1Block]) -> Result::from_asn1(keybls)?; + let (res, _) = ECCPublicKey::::from_asn1(keybls)?; return Ok(ECDSAPublic::ECCPublicP192(res)); } if oid == oid!(1,3,132,0,33) { - let (res, _) = ECCPubKey::::from_asn1(keybls)?; + let (res, _) = ECCPublicKey::::from_asn1(keybls)?; return Ok(ECDSAPublic::ECCPublicP224(res)); } if oid == oid!(1,2,840,10045,3,1,7) { - let (res, _) = ECCPubKey::::from_asn1(keybls)?; + let (res, _) = ECCPublicKey::::from_asn1(keybls)?; return Ok(ECDSAPublic::ECCPublicP256(res)); } if oid == oid!(1,3,132,0,34) { - let (res, _) = ECCPubKey::::from_asn1(keybls)?; + let (res, _) = ECCPublicKey::::from_asn1(keybls)?; return Ok(ECDSAPublic::ECCPublicP384(res)); } if oid == oid!(1,3,132,0,35) { - let (res, _) = ECCPubKey::::from_asn1(keybls)?; + let (res, _) = ECCPublicKey::::from_asn1(keybls)?; return Ok(ECDSAPublic::ECCPublicP521(res)); } } From 8a7e604fbdafc340a3d69525eecb5e84b12aa4fd Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sat, 13 Apr 2019 21:15:29 -0700 Subject: [PATCH 4/5] Make sure RSA and ECDSA have KeyPair instances. --- src/ecdsa/mod.rs | 10 ++++++++++ src/rsa/mod.rs | 10 ++++++++-- src/ssh/frame.rs | 1 - 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/ecdsa/mod.rs b/src/ecdsa/mod.rs index e10c580..f6c21e7 100644 --- a/src/ecdsa/mod.rs +++ b/src/ecdsa/mod.rs @@ -13,6 +13,7 @@ use self::point::{ECCPoint,Point}; pub use self::private::ECCPrivateKey; pub use self::public::{ECDSAPublic,ECCPublicKey}; pub use self::public::{ECDSADecodeErr,ECDSAEncodeErr}; +use super::KeyPair; pub struct ECDSAKeyPair { pub public: ECCPublicKey, @@ -21,6 +22,15 @@ pub struct ECDSAKeyPair { macro_rules! generate_impl { ($curve: ident, $un: ident, $si: ident) => { + impl KeyPair for ECDSAKeyPair<$curve> { + type Public = ECCPublicKey<$curve>; + type Private = ECCPrivateKey<$curve>; + + fn new(public: ECCPublicKey<$curve>, private: ECCPrivateKey<$curve>) -> ECDSAKeyPair<$curve> + { + ECDSAKeyPair{ public, private } + } + } impl ECDSAKeyPair<$curve> { pub fn generate(rng: &mut G) -> ECDSAKeyPair<$curve> { diff --git a/src/rsa/mod.rs b/src/rsa/mod.rs index 0221111..c2bf967 100644 --- a/src/rsa/mod.rs +++ b/src/rsa/mod.rs @@ -41,6 +41,7 @@ use cryptonum::unsigned::{CryptoNum,PrimeGen}; use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360}; use rand::RngCore; use std::ops::Sub; +use super::KeyPair; fn diff(a: &T, b: &T) -> T where @@ -62,14 +63,19 @@ pub struct RSAKeyPair { macro_rules! generate_rsa_pair { ($uint: ident, $half: ident, $iterations: expr) => { - impl RSAKeyPair<$uint> { - pub fn new(pu: RSAPublicKey<$uint>, pr: RSAPrivateKey<$uint>) -> RSAKeyPair<$uint> { + impl KeyPair for RSAKeyPair<$uint> { + type Public = RSAPublicKey<$uint>; + type Private = RSAPrivateKey<$uint>; + + fn new(pu: RSAPublicKey<$uint>, pr: RSAPrivateKey<$uint>) -> RSAKeyPair<$uint> { RSAKeyPair { public: pu, private: pr } } + } + impl RSAKeyPair<$uint> { pub fn generate(rng: &mut G) -> RSAKeyPair<$uint> where G: RngCore { diff --git a/src/ssh/frame.rs b/src/ssh/frame.rs index 49ffaea..df566d0 100644 --- a/src/ssh/frame.rs +++ b/src/ssh/frame.rs @@ -94,7 +94,6 @@ pub fn render_openssh_u32(output: &mut O, val: u32) -> Result<(),SSHKe pub fn parse_openssh_string(input: &mut I) -> Result { let length = parse_openssh_u32(input)?; - println!("len: {:X}", length); let mut limited_input = input.take(length as u64); let mut result = String::new(); limited_input.read_to_string(&mut result)?; From 6d2c803f2b07599d84729e83754765464a931b93 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sat, 13 Apr 2019 21:16:55 -0700 Subject: [PATCH 5/5] Add RSA 1024 SSH key support, as a basic attempt. --- src/ssh/mod.rs | 55 +++++++++++++++++++++++++++++++++++ src/ssh/rsa.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 src/ssh/rsa.rs diff --git a/src/ssh/mod.rs b/src/ssh/mod.rs index aa77e74..131b0e7 100644 --- a/src/ssh/mod.rs +++ b/src/ssh/mod.rs @@ -1,6 +1,7 @@ mod dsa; mod errors; mod frame; +mod rsa; pub use self::errors::{SSHKeyParseError,SSHKeyRenderError}; @@ -141,9 +142,13 @@ pub fn write_ssh_keyfile(path: P, x: &KP, comment: &str) -> Result<(),SSHK +#[cfg(test)] +use cryptonum::unsigned::{U1024}; #[cfg(test)] use dsa::{DSAKeyPair,DSAPublicKey,L1024N160}; #[cfg(test)] +use rsa::{RSAKeyPair,RSAPublicKey,SIGNING_HASH_SHA256}; +#[cfg(test)] use sha2::Sha256; #[cfg(test)] @@ -200,4 +205,54 @@ fn read_dsa_examples() { } } } +} + +#[cfg(test)] +#[test] +fn read_rsa_examples() { + let test_files = ["rsa1024-1", "rsa1024-2", "rsa1024-3"]; + + for file in test_files.iter() { + let path = format!("testdata/ssh/{}",file); + let mkeypair = load_ssh_keyfile(path); + match mkeypair { + Err(e) => assert!(false, format!("reading error: {:?}", e)), + Ok((keypair, comment)) => { + let buffer = [0,1,2,3,4,6,2]; + let _ : RSAKeyPair = keypair; + let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &buffer); + assert!(keypair.public.verify(&SIGNING_HASH_SHA256, &buffer, &sig)); + let buffer2 = [0,1,2,3,4,6,5]; + assert!(!keypair.public.verify(&SIGNING_HASH_SHA256, &buffer2, &sig)); + match encode_ssh(&keypair, &comment) { + Err(e2) => assert!(false, format!("render error: {:?}", e2)), + Ok(encodedstr) => { + match decode_ssh(&encodedstr) { + Err(e3) => assert!(false, format!("reparse error: {:?}", e3)), + Ok((keypair2,comment2)) => { + let _ : RSAKeyPair = keypair2; + assert_eq!(keypair.public.n,keypair2.public.n,"failed to reparse key pair (n)"); + assert_eq!(keypair.public.e,keypair2.public.e,"failed to reparse key pair (e)"); + assert_eq!(keypair.private.nu,keypair2.private.nu,"failed to reparse key pair (n)"); + assert_eq!(keypair.private.d,keypair2.private.d,"failed to reparse key pair (d)"); + assert_eq!(comment,comment2,"failed to reparse comment"); + let ppath = format!("testdata/ssh/{}.pub",file); + match load_ssh_pubkeys::,String>(ppath) { + Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)), + Ok(pubkeys) => { + let _ : Vec<(RSAPublicKey,String)> = pubkeys; + for (pubkey, comment3) in pubkeys { + assert_eq!(pubkey.n, keypair.public.n, "public key check (n)"); + assert_eq!(pubkey.e, keypair.public.e, "public key check (e)"); + assert_eq!(comment, comment3, "public key check comment") + } + } + } + } + } + } + } + } + } + } } \ No newline at end of file diff --git a/src/ssh/rsa.rs b/src/ssh/rsa.rs new file mode 100644 index 0000000..4e3f9cd --- /dev/null +++ b/src/ssh/rsa.rs @@ -0,0 +1,79 @@ +use cryptonum::unsigned::*; +use rsa::{RSAKeyPair,RSAPublicKey,RSAPrivateKey}; +use std::io::{Read,Write}; +use ssh::errors::{SSHKeyParseError,SSHKeyRenderError}; +use ssh::frame::*; +use ssh::SSHKey; + +impl SSHKey for RSAKeyPair { + fn valid_keytype(s: &str) -> bool { + (s == "ssh-rsa") || (s == "rsa") + } + + fn parse_ssh_public_info(inp: &mut I) -> Result + { + let pubkey_type = parse_openssh_string(inp)?; + if !Self::valid_keytype(&pubkey_type) { + return Err(SSHKeyParseError::UnknownKeyType(pubkey_type)); + } + let e = parse_openssh_number(inp)?; + let n = parse_openssh_number(inp)?; + Ok(RSAPublicKey::::new(n, e)) + } + + fn parse_ssh_private_info(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError> + { + let check1 = parse_openssh_u32(inp)?; + let check2 = parse_openssh_u32(inp)?; + if check1 != check2 { + return Err(SSHKeyParseError::PrivateKeyCorruption); + } + let privkey_type = parse_openssh_string(inp)?; + if !Self::valid_keytype(&privkey_type) { + return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-rsa".to_string(), privkey_type)); + } + let n = parse_openssh_number(inp)?; + let _e: U1024 = parse_openssh_number(inp)?; + let d = parse_openssh_number(inp)?; + let _iqmp: U1024 = parse_openssh_number(inp)?; + let _p: U1024 = parse_openssh_number(inp)?; + let _q: U1024 = parse_openssh_number(inp)?; + let comment = parse_openssh_string(inp)?; + for (idx,byte) in inp.bytes().enumerate() { + if ((idx+1) as u8) != byte? { + return Err(SSHKeyParseError::InvalidPadding); + } + } + + Ok((RSAPrivateKey::::new(n, d), comment)) + } + + fn render_ssh_public_info(&self, out: &mut O) -> Result<(),SSHKeyRenderError> + { + render_openssh_string(out, "ssh-rsa")?; + render_openssh_number(out, &self.public.e)?; + render_openssh_number(out, &self.public.n)?; + Ok(()) + } + + fn render_ssh_private_info(&self, out: &mut O, comment: &str) -> Result<(),SSHKeyRenderError> + { + render_openssh_u32(out, 0xDEADBEEF)?; // FIXME: Any reason for this to be random? + render_openssh_u32(out, 0xDEADBEEF)?; // ditto + render_openssh_string(out, "ssh-rsa")?; + render_openssh_number(out, &self.public.n)?; + render_openssh_number(out, &self.public.e)?; + render_openssh_number(out, &self.private.d)?; + render_openssh_number(out, &self.private.d)?; + render_openssh_number(out, &self.private.d)?; + render_openssh_number(out, &self.private.d)?; + render_openssh_string(out, comment)?; + // add some padding (not quite sure why) + let mut i = comment.len(); + while (i % 16) != 0 { + out.write(&[(i - comment.len() + 1) as u8])?; + i += 1; + } + Ok(()) + } +} \ No newline at end of file