1#[allow(dead_code)]
2mod hash_helper;
3pub mod bigint_helper;
4
5use std::borrow::Borrow;
6use std::ops::{Add, Mul};
7
8use num::{BigUint, Zero};
9use sha2::Sha256;
10use bigint_helper::{convert_to_bigint};
11
12
13use std::io::{Error, ErrorKind};
14use crate::hash_helper::hash;
15
16#[derive(Debug)]
17pub struct SrpConfig {
18 n: BigUint,
19 g: BigUint,
20}
21
22impl SrpConfig {
23 fn new(n: BigUint, g: BigUint) -> Self {
24 SrpConfig {
25 n,
26 g
27 }
28 }
29}
30
31fn compute_k(config: &SrpConfig) -> BigUint {
40 let k = hash::<Sha256>(&[config.n.to_bytes_be().as_slice(), config.g.to_bytes_be().as_slice()]);
41 bigint_helper::convert_to_bigint(k.as_slice(), 16).unwrap()
42}
43
44pub fn compute_x(salt: &BigUint, password: &str) -> BigUint {
56 let x = hash::<Sha256>(&[salt.to_bytes_be().as_slice(), password.as_bytes()]);
57 bigint_helper::convert_to_bigint(x.as_slice(), 16).unwrap()
58}
59
60fn compute_u(public_a: &BigUint, public_b: &BigUint) -> BigUint {
71 let hash = hash::<Sha256>(&[public_a.to_bytes_be().as_slice(), public_b.to_bytes_be().as_slice()]);
72 bigint_helper::convert_to_bigint(hash.as_slice(), 16).unwrap()
73}
74
75pub fn compute_v(srp_config: &SrpConfig, x: &BigUint) -> BigUint {
86 srp_config.g.modpow(x, &srp_config.n)
87}
88
89#[derive(Debug)]
90pub struct SrpServer {
91 srp_config: SrpConfig,
92 srp_state: SrpState,
93 username: Option<String>,
94 salt: Option<BigUint>,
95 verifier: Option<BigUint>,
96 public_b: Option<BigUint>,
97 u: Option<BigUint>,
98 public_a: BigUint,
99 ks: Option<BigUint>
100}
101
102impl SrpServer {
103 pub fn new(public_a: BigUint, n: BigUint, g: BigUint) -> Self {
104 let config = SrpConfig::new(n,g);
105 if (public_a.clone() % &config.n).is_zero() {
106 panic!("bad auth!");
107 }
108 SrpServer {
109 srp_config: config,
110 srp_state: SrpState::Init,
111 username: None,
112 salt: None,
113 verifier: None,
114 public_b: None,
115 u: None,
116 public_a,
117 ks: None
118 }
119 }
120
121 pub fn step_1(&mut self, username: String, salt: BigUint, verifier: BigUint) -> Result<BigUint, Error> {
122 if !self.srp_state.eq(&SrpState::Init) {
123 return Err(Error::new(ErrorKind::InvalidData, "wrong state!"))
124 }
125 let k = compute_k(&self.srp_config);
126 let private_b = bigint_helper::generate_random_256bit_bigint();
127 let public_b = (k.clone() * verifier.clone()) + self.srp_config.g.modpow(&private_b, &self.srp_config.n);
128 self.username = Some(username);
129 self.salt = Some(salt);
130 self.verifier = Some(verifier.clone());
131 self.u = Some(compute_u(&self.public_a, public_b.borrow()));
132 self.public_b = Some(public_b);
133 let ks = self.public_a.clone().mul(&verifier.modpow(&self.u.clone().unwrap(), &self.srp_config.n)).modpow(&private_b, &self.srp_config.n);
135 let ks = bigint_helper::convert_to_bigint(hash::<Sha256>(&[ks.clone().to_bytes_be().as_slice()]).as_slice(), 16);
136 match ks {
137 Ok(ks) => {
138 self.ks = Some(ks);
139 }
140 Err(err) => {
141 self.ks = Some(bigint_helper::generate_random_256bit_bigint());
142 }
143 }
144 self.srp_state = SrpState::Step1;
145 Ok(self.public_b.clone().unwrap())
146 }
147
148 pub fn step_2(mut self, m1: BigUint) -> Result<BigUint, Error> {
149 if !self.srp_state.eq(&SrpState::Step1) {
150 return Err(Error::new(ErrorKind::InvalidData, "wrong state!"));
151 }
152 let m1_computed = self.compute_m1()?;
153 if !m1.eq(&m1_computed) {
154 return Err(Error::new(ErrorKind::InvalidData, "bad client credentials!"));
155 }
156 self.srp_state = SrpState::Step2;
157 Ok(self.compute_m2(m1)?)
158 }
159
160 fn compute_m1(&mut self) -> Result<BigUint, Error> {
161 let m1= hash::<Sha256>(&[
162 self.public_a.clone().to_bytes_be().as_slice(),
163 self.public_b.clone().unwrap().to_bytes_be().as_slice(),
164 self.ks.clone().unwrap().to_bytes_be().as_slice()
165 ]);
166 convert_to_bigint(m1.as_slice(), 16)
167 }
168
169 fn compute_m2(&mut self, m1: BigUint) -> Result<BigUint, Error> {
170 let m_1 = hash::<Sha256>(&[
171 self.public_a.borrow().to_bytes_be().as_slice(),
172 m1.to_bytes_be().as_slice(),
173 self.ks.clone().unwrap().to_bytes_be().as_slice()
174 ]);
175 convert_to_bigint(m_1.as_slice(), 16)
176 }
177
178}
179
180#[derive(Debug)]
181pub struct SrpClient {
182 srp_config: SrpConfig,
183 srp_state: SrpState,
184 username: Option<String>,
185 password: Option<String>,
186 salt: Option<BigUint>,
187 private_a: Option<BigUint>,
188 public_a: Option<BigUint>,
189 u: Option<BigUint>,
190 public_b: Option<BigUint>,
191 kc: Option<BigUint>,
192 m1: Option<BigUint>
193}
194
195impl SrpClient {
196 pub fn new(n: BigUint, g:BigUint) -> Self {
197 SrpClient {
198 srp_config: SrpConfig::new(n,g),
199 srp_state: SrpState::Init,
200 username: None,
201 password: None,
202 salt: None,
203 private_a: None,
204 public_a: None,
205 u: None,
206 public_b: None,
207 kc: None,
208 m1: None
209
210 }
211 }
212
213 pub fn step_1(&mut self, username: String, password: String) -> Result<BigUint, Error> {
214 if !self.srp_state.eq(&SrpState::Init) {
215 return Err(Error::new(ErrorKind::InvalidData, "wrong state!"));
216 }
217 self.username = Some(username);
218 self.password = Some(password);
219 let private_a = bigint_helper::generate_random_256bit_bigint();
221 let a = self.srp_config.g.modpow(&private_a, &self.srp_config.n);
222 self.private_a = Some(private_a);
223 self.public_a = Some(a.clone());
224 self.srp_state = SrpState::Step1;
225 Ok(a)
226 }
227
228 pub fn step_2(&mut self, salt: BigUint, public_b: BigUint) -> Result<BigUint, Error> {
229 if !self.srp_state.eq(&SrpState::Step1) {
230 panic!("bad srp state!")
231 }
232 let u = compute_u(&self.public_a.as_mut().unwrap(), &public_b);
233 if public_b.clone().is_zero() || u.clone().is_zero() {
234 panic!("bad client auth!");
235 }
236 self.u = Some(u.clone());
237 self.salt = Some(salt.clone());
238 self.public_b = Some(public_b.clone());
239 let x = compute_x(&salt, self.password.clone().unwrap().as_str());
240 let k = compute_k(&self.srp_config);
241 let tmp = (self.srp_config.g.clone().modpow(&x, &self.srp_config.n)) * k;
243 if public_b < tmp {
244 panic!("bad client auth!");
245 }
246 let sc = (public_b - tmp)
247 .modpow(&(self.private_a.clone().unwrap().add(&u.mul(&x))), &self.srp_config.n);
248 let kc = bigint_helper::convert_to_bigint(hash::<Sha256>(&[sc.borrow().to_bytes_be().as_slice()]).as_slice(), 16).unwrap();
249 self.kc = Some(kc);
250 let m_1 = self.compute_m1()?;
251 self.m1 = Some(m_1.clone());
252 self.srp_state = SrpState::Step2;
253 Ok(m_1)
254 }
255
256 pub fn step_3(mut self, m2: BigUint) -> Result<(), Error> {
257 if !self.srp_state.eq(&SrpState::Step2) {
258 return Err(Error::new(ErrorKind::InvalidData, "wrong state!"));
259 }
260 let computed_m2 = self.compute_m2(self.m1.clone().unwrap())?;
261 if !m2.eq(&computed_m2) {
262 return Err(Error::new(ErrorKind::InvalidData, "bad credentials!"));
263 }
264 Ok(())
265 }
266
267
268 fn compute_m1(&mut self) -> Result<BigUint, Error> {
269 let m_1 = hash::<Sha256>(&[
270 self.public_a.clone().unwrap().clone().to_bytes_be().as_slice(),
271 self.public_b.clone().unwrap().clone().to_bytes_be().as_slice(),
272 self.kc.clone().unwrap().clone().to_bytes_be().as_slice()]);
273 convert_to_bigint(m_1.as_slice(), 16)
274 }
275
276 fn compute_m2(&mut self, m1: BigUint) -> Result<BigUint, Error> {
277 let m_1 = hash::<Sha256>(&[
278 self.public_a.clone().unwrap().to_bytes_be().as_slice(),
279 m1.to_bytes_be().as_slice(),
280 self.kc.clone().unwrap().to_bytes_be().as_slice()
281 ]);
282 convert_to_bigint(m_1.as_slice(), 16)
283 }
284}
285
286#[derive(Debug, PartialEq)]
287enum SrpState {
288 Init, Step1, Step2
289}
290
291#[cfg(test)]
292mod tests {
293 use core::iter;
294
295 use rand::{Rng, thread_rng};
296 use rand::distributions::Alphanumeric;
297
298 use super::*;
299 use std::time::SystemTime;
300
301 #[test]
302 fn test_srp_config() {
303 let n = BigUint::parse_bytes(b"C41C06B5D64E368D2581D791A0233577795106D623130526BFE23528BBE95F1E5F80A6555CD1E5A29FB2FA49547072C7B6D9147C4F8B2209424FBB95DBF70BBB", 16).unwrap();
304 let g = BigUint::parse_bytes(b"2", 10).unwrap();
305 let config = SrpConfig::new(n,g);
306 println!("{:?}", config);
307 }
308
309 #[test]
310 fn test_srp_generate_verifier() {
311 let salt = bigint_helper::generate_random_256bit_bigint();
312 let x = compute_x(&salt,"pass123");
313 println!("private key = {:?}", x);
314 let n = BigUint::parse_bytes(b"C41C06B5D64E368D2581D791A0233577795106D623130526BFE23528BBE95F1E5F80A6555CD1E5A29FB2FA49547072C7B6D9147C4F8B2209424FBB95DBF70BBB", 16).unwrap();
315 let g = BigUint::parse_bytes(b"2", 10).unwrap();
316 let verifier = compute_v(&SrpConfig::new(n,g),&x);
317 println!("verifier = {:?}", verifier)
318 }
319
320 #[test]
321 fn test_srp_client_server() {
322 const SIZE: usize = 100;
323 let mut users = vec![];
324 let mut rng = thread_rng();
325 for index in 0..SIZE {
326 let salt = bigint_helper::generate_random_256bit_bigint();
327 let identity: String = iter::repeat(())
328 .map(|()| rng.sample(Alphanumeric))
329 .map(char::from)
330 .take(7)
331 .collect();
332 let password: String = iter::repeat(())
333 .map(|()| rng.sample(Alphanumeric))
334 .map(char::from)
335 .take(7)
336 .collect();
337
338 let x = compute_x(&salt, password.as_str());
339 let n = BigUint::parse_bytes(b"C41C06B5D64E368D2581D791A0233577795106D623130526BFE23528BBE95F1E5F80A6555CD1E5A29FB2FA49547072C7B6D9147C4F8B2209424FBB95DBF70BBB", 16).unwrap();
340 let g = BigUint::parse_bytes(b"2", 10).unwrap();
341 let verifier = compute_v(&SrpConfig::new(n,g), &x);
342 users.push(User {
343 salt,
344 verifier,
345 username: identity,
346 password
347 });
348 }
349
350 let now = SystemTime::now();
351 for (index, user) in users.iter().enumerate() {
352 let n = BigUint::parse_bytes(b"C41C06B5D64E368D2581D791A0233577795106D623130526BFE23528BBE95F1E5F80A6555CD1E5A29FB2FA49547072C7B6D9147C4F8B2209424FBB95DBF70BBB", 16).unwrap();
353 let g = BigUint::parse_bytes(b"2", 10).unwrap();
354 let mut client = SrpClient::new(n.clone(),g.clone());
355 let a = client.step_1(user.username.clone(), user.password.clone());
357 match a {
358 Ok(a) => {
359 let mut server = SrpServer::new(a, n.clone(), g.clone());
361 let b = server.step_1(user.username.clone(), user.salt.clone(), user.verifier.clone());
363 match b {
364 Ok(b) => {
365 let m_1 = client.step_2(user.salt.clone(), b.clone());
368 match m_1 {
369 Ok(m_1) => {
370 let m_2 = server.step_2(m_1);
372 match m_2 {
373 Ok(m_2) => {
374 match client.step_3(m_2) {
375 Ok(_) => {}
376 Err(err) => {
377 panic!("{}", err);
378 }
379 };
380 }
381 Err(err) => {
382 panic!("{}", err);
383 }
384 }
385 }
386 Err(err) => {
387 panic!("{}", err);
388 }
389 }
390
391 }
392 Err(err) => {
393 panic!("{}", err);
394 }
395 }
396 }
397 Err(err) => {
398 panic!("{}", err);
399 }
400 }
401 }
402 }
403
404
405 struct User {
406 username: String,
407 password: String,
408 salt: BigUint,
409 verifier: BigUint
410 }
411}
412
413