From 30185898f55f87b5d79ad231f80d26054fcc2ec4 Mon Sep 17 00:00:00 2001 From: palaviv Date: Tue, 12 Jul 2016 21:18:00 +0300 Subject: [PATCH 1/4] dh: Diffie-Hellman key exchange support --- Cargo.toml | 1 + src/dh.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + 3 files changed, 113 insertions(+) create mode 100644 src/dh.rs diff --git a/Cargo.toml b/Cargo.toml index 8ea941a7..cc23c93a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,4 @@ libc = "^0.2" time = "^0.1" rand = "^0.3" rustc-serialize = "^0.3" +num = "^0.1" diff --git a/src/dh.rs b/src/dh.rs new file mode 100644 index 00000000..2e03bdf3 --- /dev/null +++ b/src/dh.rs @@ -0,0 +1,110 @@ +use rand; + +use num::{BigUint, Zero}; +use num::bigint::RandBigInt; +use num::cast::FromPrimitive; + + +fn modular_power(mut base: BigUint, mut exponent: BigUint, modulos: &BigUint) -> BigUint { + let one = BigUint::from_u32(1 as u32).expect("Could not convert 1"); + if modulos == &one { + return one; + } + let mut result = one.clone(); + base = base % modulos; + while exponent > BigUint::zero() { + if &exponent % BigUint::from_u32(2 as u32).expect("Could not convert 2") == one { + result = (&result * &base) % modulos; + } + exponent = exponent >> 1; + base = (&base * &base) % modulos; + } + + result +} + +pub struct DHPublicKey { + pub_key: BigUint, +} + +pub struct DHPrivateKey<'a> { + params: &'a DHParameters, + priv_key: BigUint, +} + +impl DHPublicKey { + pub fn key(&self) -> Vec { + self.pub_key.to_bytes_le() + } +} + +impl<'a> DHPrivateKey<'a> { + pub fn key(&self) -> Vec { + self.priv_key.to_bytes_le() + } + + pub fn public_key(&self) -> DHPublicKey { + let pub_key = modular_power(self.params.g.clone(), self.priv_key.clone(), &self.params.p); + + DHPublicKey { + pub_key: pub_key + } + } + + pub fn exchange(&self, pub_key: &DHPublicKey) -> BigUint { + modular_power(pub_key.pub_key.clone(), self.priv_key.clone(), &self.params.p) + } +} + +pub struct DHParameters { + p: BigUint, + g: BigUint, +} + +impl DHParameters { + pub fn private_key(&self) -> DHPrivateKey { + let mut rng = match rand::OsRng::new() { + Ok(g) => g, + Err(e) => panic!("Could not load the OS' RNG! Error: {}", e) + }; + + let priv_key = rng.gen_biguint_below(&self.p); + DHPrivateKey { + params: self, + priv_key: priv_key + } + } +} + + +#[cfg(test)] +mod tests { + use dh::{DHParameters, modular_power}; + use num::{BigUint}; + use num::cast::{FromPrimitive}; + + #[test] + fn test_modular_power() { + let base = BigUint::from_u32(4 as u32).expect("Could not convert base"); + let exp = BigUint::from_u32(13 as u32).expect("Could not convert exp"); + let modulos = BigUint::from_u32(497 as u32).expect("Could not convert modulos"); + assert_eq!(modular_power(base, exp, &modulos), BigUint::from_u32(445 as u32). + expect("Could not convert result")) + } + + #[test] + fn test_exchange(){ + let params = DHParameters { + p: BigUint::from_u32(23 as u32).expect("Could not convert p"), + g: BigUint::from_u32(5 as u32).expect("Could not convert g") + }; + let priv_key1 = params.private_key(); + let priv_key2 = params.private_key(); + let pub_key1 = priv_key1.public_key(); + let pub_key2 = priv_key2.public_key(); + let shared_key1 = priv_key2.exchange(&pub_key1); + let shared_key2 = priv_key1.exchange(&pub_key2); + assert!(shared_key1 == shared_key2); + } + +} diff --git a/src/lib.rs b/src/lib.rs index 59ad3afb..a58402cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate rand; extern crate rustc_serialize as serialize; extern crate time; extern crate libc; +extern crate num; #[cfg(all(test, feature = "with-bench"))] extern crate test; @@ -53,6 +54,7 @@ mod step_by; pub mod symmetriccipher; pub mod util; pub mod whirlpool; +pub mod dh; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub mod aesni; From f9d88134e45c7f20fde9dc2814899ca30507b965 Mon Sep 17 00:00:00 2001 From: palaviv Date: Tue, 12 Jul 2016 22:04:24 +0300 Subject: [PATCH 2/4] dh: Use of num:BigUint is opaque --- src/dh.rs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/dh.rs b/src/dh.rs index 2e03bdf3..e41df0f2 100644 --- a/src/dh.rs +++ b/src/dh.rs @@ -27,6 +27,14 @@ pub struct DHPublicKey { pub_key: BigUint, } +impl DHPublicKey { + pub fn new(pub_key: &[u8]) -> DHPublicKey { + DHPublicKey { + pub_key: BigUint::from_bytes_be(pub_key) + } + } +} + pub struct DHPrivateKey<'a> { params: &'a DHParameters, priv_key: BigUint, @@ -34,13 +42,13 @@ pub struct DHPrivateKey<'a> { impl DHPublicKey { pub fn key(&self) -> Vec { - self.pub_key.to_bytes_le() + self.pub_key.to_bytes_be() } } impl<'a> DHPrivateKey<'a> { pub fn key(&self) -> Vec { - self.priv_key.to_bytes_le() + self.priv_key.to_bytes_be() } pub fn public_key(&self) -> DHPublicKey { @@ -51,8 +59,9 @@ impl<'a> DHPrivateKey<'a> { } } - pub fn exchange(&self, pub_key: &DHPublicKey) -> BigUint { - modular_power(pub_key.pub_key.clone(), self.priv_key.clone(), &self.params.p) + pub fn exchange(&self, pub_key: &DHPublicKey) -> Vec { + let shared_key = modular_power(pub_key.pub_key.clone(), self.priv_key.clone(), &self.params.p); + shared_key.to_bytes_be() } } @@ -62,6 +71,13 @@ pub struct DHParameters { } impl DHParameters { + pub fn new(p: &[u8], g: u64) -> DHParameters { + DHParameters { + p: BigUint::from_bytes_be(p), + g: BigUint::from_u64(g).expect("Could not convert g") + } + } + pub fn private_key(&self) -> DHPrivateKey { let mut rng = match rand::OsRng::new() { Ok(g) => g, @@ -94,10 +110,7 @@ mod tests { #[test] fn test_exchange(){ - let params = DHParameters { - p: BigUint::from_u32(23 as u32).expect("Could not convert p"), - g: BigUint::from_u32(5 as u32).expect("Could not convert g") - }; + let params = DHParameters::new(&[0x17], 5); let priv_key1 = params.private_key(); let priv_key2 = params.private_key(); let pub_key1 = priv_key1.public_key(); From e4659af7662b592addaa72ea8ff4ab6b24d17e82 Mon Sep 17 00:00:00 2001 From: palaviv Date: Tue, 12 Jul 2016 22:34:27 +0300 Subject: [PATCH 3/4] dh: Added RFC2049 consts --- src/dh.rs | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/dh.rs b/src/dh.rs index e41df0f2..dc635136 100644 --- a/src/dh.rs +++ b/src/dh.rs @@ -4,6 +4,37 @@ use num::{BigUint, Zero}; use num::bigint::RandBigInt; use num::cast::FromPrimitive; +// From rfc 2409 (https://tools.ietf.org/html/rfc2409). +pub const RFC2409_PRIME_768: [u8; 96] = [ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + ]; + +pub const RFC2409_GENERATOR_768: u64 = 2; + +pub const RFC2409_PRIME_1024: [u8; 128] = [ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + ]; + +pub const RFC2409_GENERATOR_1024: u64 = 2; + + fn modular_power(mut base: BigUint, mut exponent: BigUint, modulos: &BigUint) -> BigUint { let one = BigUint::from_u32(1 as u32).expect("Could not convert 1"); @@ -95,7 +126,8 @@ impl DHParameters { #[cfg(test)] mod tests { - use dh::{DHParameters, modular_power}; + use dh::{DHParameters, modular_power, RFC2409_PRIME_768, RFC2409_GENERATOR_768, + RFC2409_PRIME_1024, RFC2409_GENERATOR_1024}; use num::{BigUint}; use num::cast::{FromPrimitive}; @@ -108,9 +140,7 @@ mod tests { expect("Could not convert result")) } - #[test] - fn test_exchange(){ - let params = DHParameters::new(&[0x17], 5); + fn test_exhange_with_params(params: &DHParameters) { let priv_key1 = params.private_key(); let priv_key2 = params.private_key(); let pub_key1 = priv_key1.public_key(); @@ -120,4 +150,11 @@ mod tests { assert!(shared_key1 == shared_key2); } + #[test] + fn test_exchange() { + test_exhange_with_params(&DHParameters::new(&[0x17], 5)); + test_exhange_with_params(&DHParameters::new(&RFC2409_PRIME_768, RFC2409_GENERATOR_768)); + test_exhange_with_params(&DHParameters::new(&RFC2409_PRIME_1024, RFC2409_GENERATOR_1024)); + } + } From 816eb9a45791e19216f340d3fbd1eb61dd40f0b1 Mon Sep 17 00:00:00 2001 From: palaviv Date: Fri, 15 Jul 2016 14:05:32 +0300 Subject: [PATCH 4/4] dh: Private key bits length is that same as p --- src/dh.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/dh.rs b/src/dh.rs index dc635136..b52f4f83 100644 --- a/src/dh.rs +++ b/src/dh.rs @@ -1,6 +1,6 @@ use rand; -use num::{BigUint, Zero}; +use num::{BigUint, Zero, One}; use num::bigint::RandBigInt; use num::cast::FromPrimitive; @@ -37,11 +37,11 @@ pub const RFC2409_GENERATOR_1024: u64 = 2; fn modular_power(mut base: BigUint, mut exponent: BigUint, modulos: &BigUint) -> BigUint { - let one = BigUint::from_u32(1 as u32).expect("Could not convert 1"); + let one = BigUint::one(); if modulos == &one { return one; } - let mut result = one.clone(); + let mut result = BigUint::one(); base = base % modulos; while exponent > BigUint::zero() { if &exponent % BigUint::from_u32(2 as u32).expect("Could not convert 2") == one { @@ -109,13 +109,21 @@ impl DHParameters { } } + pub fn key_length(&self) -> usize { + self.p.bits() + } + pub fn private_key(&self) -> DHPrivateKey { let mut rng = match rand::OsRng::new() { Ok(g) => g, Err(e) => panic!("Could not load the OS' RNG! Error: {}", e) }; - let priv_key = rng.gen_biguint_below(&self.p); + let mut priv_key = rng.gen_biguint(self.key_length()); + while (priv_key == BigUint::one()) || (priv_key == BigUint::zero()) { + priv_key = rng.gen_biguint(self.key_length()); + } + DHPrivateKey { params: self, priv_key: priv_key