summaryrefslogtreecommitdiffstats
path: root/src/dh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/dh.rs')
-rw-r--r--src/dh.rs158
1 files changed, 158 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)
+ }
+}