From 00d7d43e619a6bebe17459e620edd2d123c84bcf Mon Sep 17 00:00:00 2001 From: Masih Yeganeh Date: Wed, 7 Oct 2020 22:45:18 +0330 Subject: Bump digest, sha-1, and sha2 dependencies to v0.9 (#37) --- srp/src/client.rs | 128 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 40 deletions(-) (limited to 'srp/src/client.rs') diff --git a/srp/src/client.rs b/srp/src/client.rs index a33f9b3..a9f7564 100644 --- a/srp/src/client.rs +++ b/srp/src/client.rs @@ -58,8 +58,7 @@ //! ``` use std::marker::PhantomData; -use digest::Digest; -use generic_array::GenericArray; +use digest::{Digest, Output}; use num_bigint::BigUint; use crate::tools::powm; @@ -77,29 +76,25 @@ pub struct SrpClient<'a, D: Digest> { /// SRP client state after handshake with the server. pub struct SrpClientVerifier { - proof: GenericArray, - server_proof: GenericArray, - key: GenericArray, + proof: Output, + server_proof: Output, + key: Output, } /// Compute user private key as described in the RFC 5054. Consider using proper /// password hashing algorithm instead. -pub fn srp_private_key( - username: &[u8], - password: &[u8], - salt: &[u8], -) -> GenericArray { +pub fn srp_private_key(username: &[u8], password: &[u8], salt: &[u8]) -> Output { let p = { let mut d = D::new(); - d.input(username); - d.input(b":"); - d.input(password); - d.result() + d.update(username); + d.update(b":"); + d.update(password); + d.finalize() }; let mut d = D::new(); - d.input(salt); - d.input(&p); - d.result() + d.update(salt); + d.update(p.as_slice()); + d.finalize() } impl<'a, D: Digest> SrpClient<'a, D> { @@ -123,12 +118,7 @@ impl<'a, D: Digest> SrpClient<'a, D> { v.to_bytes_be() } - fn calc_key( - &self, - b_pub: &BigUint, - x: &BigUint, - u: &BigUint, - ) -> GenericArray { + fn calc_key(&self, b_pub: &BigUint, x: &BigUint, u: &BigUint) -> Output { let n = &self.params.n; let k = self.params.compute_k::(); let interm = (k * self.params.powm(x)) % n; @@ -151,9 +141,10 @@ impl<'a, D: Digest> SrpClient<'a, D> { ) -> Result, SrpAuthError> { let u = { let mut d = D::new(); - d.input(&self.a_pub.to_bytes_be()); - d.input(b_pub); - BigUint::from_bytes_be(&d.result()) + d.update(&self.a_pub.to_bytes_be()); + d.update(b_pub); + let h = d.finalize(); + BigUint::from_bytes_be(h.as_slice()) }; let b_pub = BigUint::from_bytes_be(b_pub); @@ -170,19 +161,79 @@ impl<'a, D: Digest> SrpClient<'a, D> { // M1 = H(A, B, K) let proof = { let mut d = D::new(); - d.input(&self.a_pub.to_bytes_be()); - d.input(&b_pub.to_bytes_be()); - d.input(&key); - d.result() + d.update(&self.a_pub.to_bytes_be()); + d.update(&b_pub.to_bytes_be()); + d.update(&key); + d.finalize() }; // M2 = H(A, M1, K) let server_proof = { let mut d = D::new(); - d.input(&self.a_pub.to_bytes_be()); - d.input(&proof); - d.input(&key); - d.result() + d.update(&self.a_pub.to_bytes_be()); + d.update(&proof); + d.update(&key); + d.finalize() + }; + + Ok(SrpClientVerifier { + proof, + server_proof, + key, + }) + } + + /// Process server reply to the handshake with username and salt. + pub fn process_reply_with_username_and_salt( + self, + username: &[u8], + salt: &[u8], + private_key: &[u8], + b_pub: &[u8], + ) -> Result, SrpAuthError> { + let u = { + let mut d = D::new(); + d.update(&self.a_pub.to_bytes_be()); + d.update(b_pub); + let h = d.finalize(); + BigUint::from_bytes_be(h.as_slice()) + }; + + let b_pub = BigUint::from_bytes_be(b_pub); + + // Safeguard against malicious B + if &b_pub % &self.params.n == BigUint::default() { + return Err(SrpAuthError { + description: "Malicious b_pub value", + }); + } + + let x = BigUint::from_bytes_be(private_key); + let key = self.calc_key(&b_pub, &x, &u); + // M1 = H(H(N)^H(g), H(I), salt, A, B, K) + let proof = { + let mut d = D::new(); + d.update(username); + let h = d.finalize_reset(); + let I: &[u8] = h.as_slice(); + + d.update(self.params.compute_hash_n_xor_hash_g::()); + d.update(I); + d.update(salt); + d.update(&self.a_pub.to_bytes_be()); + d.update(&b_pub.to_bytes_be()); + d.update(&key.to_vec()); + d.finalize() + }; + let x = proof.to_vec().as_slice(); + + // M2 = H(A, M1, K) + let server_proof = { + let mut d = D::new(); + d.update(&self.a_pub.to_bytes_be()); + d.update(&proof); + d.update(&key); + d.finalize() }; Ok(SrpClientVerifier { @@ -202,21 +253,18 @@ impl SrpClientVerifier { /// Get shared secret key without authenticating server, e.g. for using with /// authenticated encryption modes. DO NOT USE this method without /// some kind of secure authentication - pub fn get_key(self) -> GenericArray { + pub fn get_key(self) -> Output { self.key } /// Verification data for sending to the server. - pub fn get_proof(&self) -> GenericArray { + pub fn get_proof(&self) -> Output { self.proof.clone() } /// Verify server reply to verification data. It will return shared secret /// key in case of success. - pub fn verify_server( - self, - reply: &[u8], - ) -> Result, SrpAuthError> { + pub fn verify_server(self, reply: &[u8]) -> Result, SrpAuthError> { if self.server_proof.as_slice() != reply { Err(SrpAuthError { description: "Incorrect server proof", -- cgit v1.2.3