From 8cc9f7dbcd1bb27848786afd94ff1d2199a231a6 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 22 May 2019 00:36:02 -0400 Subject: problem 36 --- src/dh.rs | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ tests/set5.rs | 27 ++++++++++ 3 files changed, 188 insertions(+) diff --git a/src/dh.rs b/src/dh.rs index 5e368d9..5317b29 100644 --- a/src/dh.rs +++ b/src/dh.rs @@ -1,4 +1,5 @@ use num_bigint::RandBigInt; +use rand::Rng; #[derive(Debug)] pub struct DHKeyPair { @@ -27,3 +28,160 @@ impl DHKeyPair { other_pubkey.modpow(self.privkey.as_ref().unwrap(), &self.p) } } + +#[derive(Debug)] +pub struct SRPServer { + users: std::collections::HashMap, + sessions: std::collections::HashMap, SRPSession>, + n: num_bigint::BigUint, + g: num_bigint::BigUint, + k: num_bigint::BigUint, +} + +impl SRPServer { + pub fn new( + n: num_bigint::BigUint, + g: num_bigint::BigUint, + k: num_bigint::BigUint, + ) -> SRPServer { + SRPServer { + users: std::collections::HashMap::new(), + sessions: std::collections::HashMap::new(), + n, + g, + k, + } + } + + pub fn register( + &mut self, + identity: &str, + salt: &[u8], + verifier: &num_bigint::BigUint, + ) { + self.users + .insert(identity.to_string(), SRPUser::new(salt, verifier)); + } + + pub fn exchange_pubkeys( + &mut self, + user: &str, + a_pub: &num_bigint::BigUint, + ) -> (Vec, Vec, num_bigint::BigUint) { + let userdata = self.users.get(user).unwrap(); + let b_priv = rand::thread_rng().gen_biguint_below(&self.n); + let kv = self.k.clone() * userdata.verifier.clone(); + let b_pub = self.g.modpow(&b_priv, &self.n) + kv; + + let session = SRPSession { + a_pub: a_pub.clone(), + b_priv: b_priv, + b_pub: b_pub.clone(), + v: userdata.verifier.clone(), + salt: userdata.salt.clone(), + }; + let mut session_key = [0; 16]; + rand::thread_rng().fill(&mut session_key); + let session_key = session_key.to_vec(); + self.sessions.insert(session_key.clone(), session); + + (session_key, userdata.salt.to_vec(), b_pub) + } + + pub fn verify(&mut self, session: Vec, hmac: Vec) -> bool { + let n = &self.n.clone(); + + let session = self.sessions.get(&session).unwrap(); + + let uinput = + [session.a_pub.to_bytes_le(), session.b_pub.to_bytes_le()] + .concat(); + let uh = crate::sha1::sha1(&uinput); + let u = num_bigint::BigUint::from_bytes_le(&uh[..]); + + let s = (session.a_pub.clone() * session.v.modpow(&u, n)) + .modpow(&session.b_priv, n); + let k = crate::sha1::sha1(&s.to_bytes_le()); + let server_hmac = crate::sha1::sha1_hmac(&k, &session.salt); + + hmac == server_hmac + } +} + +#[derive(Debug)] +pub struct SRPUser { + salt: Vec, + verifier: num_bigint::BigUint, +} + +impl SRPUser { + pub fn new(salt: &[u8], verifier: &num_bigint::BigUint) -> SRPUser { + SRPUser { + salt: salt.to_vec(), + verifier: verifier.clone(), + } + } +} + +#[derive(Debug)] +pub struct SRPSession { + a_pub: num_bigint::BigUint, + b_priv: num_bigint::BigUint, + b_pub: num_bigint::BigUint, + v: num_bigint::BigUint, + salt: Vec, +} + +#[derive(Debug)] +pub struct SRPClient<'a> { + server: &'a mut SRPServer, +} + +impl<'a> SRPClient<'a> { + pub fn new(server: &'a mut SRPServer) -> SRPClient<'a> { + SRPClient { server } + } + + pub fn register(&mut self, user: &str, pass: &str) { + let mut salt = [0; 16]; + rand::thread_rng().fill(&mut salt); + let input = [&salt[..], pass.as_bytes()].concat(); + let xh = crate::sha1::sha1(&input); + let x = num_bigint::BigUint::from_bytes_le(&xh[..]); + let v = self.server.g.modpow(&x, &self.server.n); + self.server.register(user, &salt, &v); + } + + pub fn key_exchange( + &mut self, + user: &str, + pass: &str, + ) -> Option { + let n = &self.server.n.clone(); + let g = &self.server.g.clone(); + let k = &self.server.k.clone(); + + let a_priv = rand::thread_rng().gen_biguint_below(n); + let a_pub = g.modpow(&a_priv, n); + let (session, salt, b_pub) = + self.server.exchange_pubkeys(user, &a_pub); + + let uinput = [a_pub.to_bytes_le(), b_pub.to_bytes_le()].concat(); + let uh = crate::sha1::sha1(&uinput); + let u = num_bigint::BigUint::from_bytes_le(&uh[..]); + + let xinput = [salt.clone(), pass.as_bytes().to_vec()].concat(); + let xh = crate::sha1::sha1(&xinput); + let x = num_bigint::BigUint::from_bytes_le(&xh[..]); + + let s = (b_pub - k * g.modpow(&x, n)).modpow(&(a_priv + u * x), n); + let k = crate::sha1::sha1(&s.to_bytes_le()); + let hmac = crate::sha1::sha1_hmac(&k, &salt); + + if !self.server.verify(session, hmac.to_vec()) { + return None + } + + Some(s) + } +} diff --git a/src/lib.rs b/src/lib.rs index 8f98763..d7566e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,9 @@ pub use crack::DiffieHellmanMessageExchanger; pub use crack::NullDiffieHellmanMessageExchanger; pub use crack::ParameterInjectionDiffieHellmanMessageExchanger; pub use dh::DHKeyPair; +pub use dh::SRPClient; +pub use dh::SRPServer; +pub use dh::SRPUser; pub use http::create_query_string; pub use http::parse_query_string; pub use md4::md4; diff --git a/tests/set5.rs b/tests/set5.rs index 8cab7df..6aa089a 100644 --- a/tests/set5.rs +++ b/tests/set5.rs @@ -232,3 +232,30 @@ fn run_dh_message_exchange( }) .unwrap(); } + +#[test] +fn problem_36() { + let n_hex = "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024\ + e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd\ + 3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec\ + 6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f\ + 24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361\ + c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552\ + bb9ed529077096966d670c354e4abc9804f1746c08ca237327fff\ + fffffffffffff"; + let n = num_bigint::BigUint::parse_bytes(n_hex.as_bytes(), 16).unwrap(); + let g = num_bigint::BigUint::from(2 as u8); + let k = num_bigint::BigUint::from(3 as u8); + + let user = "doy@tozt.net"; + let pass = "supersecret"; + + let mut server = matasano::SRPServer::new(n, g, k); + let mut client = matasano::SRPClient::new(&mut server); + + client.register(user, pass); + + let key = client.key_exchange(user, pass); + + assert!(key.is_some()); +} -- cgit v1.2.3