@@ -85,7 +85,8 @@ use subtle::ConstantTimeEq;
8585
8686use crate::types::{SrpAuthError, SrpGroup};
8787use crate::utils::{
88- compute_hash, compute_k, compute_m1, compute_m1_rfc5054, compute_m2, compute_u,
88+ compute_hash, compute_k, compute_k_nopad, compute_m1, compute_m1_csrp, compute_m1_rfc5054,
89+ compute_m2, compute_u,
8990};
9091
9192/// SRP server state
@@ -126,6 +127,13 @@ impl<'a, D: Digest> SrpServer<'a, D> {
126127 (inter + self.params.g.modpow(b, &self.params.n)) % &self.params.n
127128 }
128129
130+ // k*v + g^b
131+ #[must_use]
132+ pub fn compute_b_pub_csrp(&self, b: &BigUint, k: &BigUint, v: &BigUint) -> BigUint {
133+ let inter = k * v;
134+ inter + self.params.g.modpow(b, &self.params.n)
135+ }
136+
129137 // <premaster secret> = (A * v^u) ^ b % N
130138 #[must_use]
131139 pub fn compute_premaster_secret(
@@ -151,6 +159,16 @@ impl<'a, D: Digest> SrpServer<'a, D> {
151159 .to_bytes_be()
152160 }
153161
162+ #[must_use]
163+ pub fn compute_public_ephemeral_csrp(&self, b: &[u8], v: &[u8]) -> Vec<u8> {
164+ self.compute_b_pub_csrp(
165+ &BigUint::from_bytes_be(b),
166+ &compute_k::<D>(self.params),
167+ &BigUint::from_bytes_be(v),
168+ )
169+ .to_bytes_be()
170+ }
171+
154172 /// Process client reply to the handshake.
155173 /// b is a random value,
156174 /// v is the provided during initial user registration
@@ -240,6 +258,56 @@ impl<'a, D: Digest> SrpServer<'a, D> {
240258 session_key: session_key.to_vec(),
241259 })
242260 }
261+
262+ /// Process client reply to the handshake according to RFC 5054.
263+ /// b is a random value,
264+ /// v is the provided during initial user registration
265+ pub fn process_reply_csrp(
266+ &self,
267+ username: &[u8],
268+ salt: &[u8],
269+ b: &[u8],
270+ v: &[u8],
271+ a_pub: &[u8],
272+ ) -> Result<SrpServerVerifierRfc5054<D>, SrpAuthError> {
273+ let b = BigUint::from_bytes_be(b);
274+ let v = BigUint::from_bytes_be(v);
275+ let a_pub = BigUint::from_bytes_be(a_pub);
276+
277+ let k = compute_k_nopad::<D>(self.params);
278+ let b_pub = self.compute_b_pub_csrp(&b, &k, &v);
279+
280+ // Safeguard against malicious A
281+ if &a_pub % &self.params.n == BigUint::default() {
282+ return Err(SrpAuthError::IllegalParameter("a_pub".to_owned()));
283+ }
284+
285+ let u = compute_u::<D>(&a_pub.to_bytes_be(), &b_pub.to_bytes_be());
286+
287+ let premaster_secret = self
288+ .compute_premaster_secret(&a_pub, &v, &u, &b)
289+ .to_bytes_be();
290+
291+ let session_key = compute_hash::<D>(&premaster_secret);
292+
293+ let m1 = compute_m1_csrp::<D>(
294+ self.params,
295+ username,
296+ salt,
297+ &a_pub.to_bytes_be(),
298+ &b_pub.to_bytes_be(),
299+ session_key.as_slice(),
300+ );
301+
302+ let m2 = compute_m2::<D>(&a_pub.to_bytes_be(), &m1, session_key.as_slice());
303+
304+ Ok(SrpServerVerifierRfc5054 {
305+ m1,
306+ m2,
307+ key: premaster_secret,
308+ session_key: session_key.to_vec(),
309+ })
310+ }
243311}
244312
245313impl<D: Digest> SrpServerVerifier<D> {
0 commit comments