summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-05-22 00:36:02 -0400
committerJesse Luehrs <doy@tozt.net>2019-05-22 00:36:02 -0400
commit8cc9f7dbcd1bb27848786afd94ff1d2199a231a6 (patch)
tree65f1c09e4a0bccb007387d43deba806b14fafedf
parent1c663ca4e0cf4584e941e18d967d38ee628c9e0d (diff)
downloadmatasano-8cc9f7dbcd1bb27848786afd94ff1d2199a231a6.tar.gz
matasano-8cc9f7dbcd1bb27848786afd94ff1d2199a231a6.zip
problem 36
-rw-r--r--src/dh.rs158
-rw-r--r--src/lib.rs3
-rw-r--r--tests/set5.rs27
3 files changed, 188 insertions, 0 deletions
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<String, SRPUser>,
+ sessions: std::collections::HashMap<Vec<u8>, 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<u8>, Vec<u8>, 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<u8>, hmac: Vec<u8>) -> 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<u8>,
+ 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<u8>,
+}
+
+#[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<num_bigint::BigUint> {
+ 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<T>(
})
.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());
+}