From b7e3e688c841fa25960665247fa54bfa9cf70e2f Mon Sep 17 00:00:00 2001 From: Brenden Matthews Date: Tue, 13 Aug 2019 13:49:10 -0400 Subject: [PATCH 1/2] Implement proof generation as per RFC2945. This is a backward-incompatible change. For details, refer to: - https://tools.ietf.org/html/rfc2945 - https://tools.ietf.org/html/rfc5054 - http://srp.stanford.edu/design.html - https://github.com/RustCrypto/PAKEs/issues/20 This resolves issue #20. --- srp/src/client.rs | 24 +++++++++++++++++++++++- srp/src/server.rs | 48 +++++++++++++++++++++++++++++++++++++---------- srp/tests/mod.rs | 4 +++- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/srp/src/client.rs b/srp/src/client.rs index 6cc1d7f..df956f2 100644 --- a/srp/src/client.rs +++ b/srp/src/client.rs @@ -146,6 +146,8 @@ impl<'a, D: Digest> SrpClient<'a, D> { /// Process server reply to the handshake. pub fn process_reply( self, + username: &[u8], + salt: &[u8], private_key: &[u8], b_pub: &[u8], ) -> Result, SrpAuthError> { @@ -167,9 +169,29 @@ impl<'a, D: Digest> SrpClient<'a, D> { let x = BigUint::from_bytes_be(private_key); let key = self.calc_key(&b_pub, &x, &u); - // M1 = H(A, B, K) + // M = H(H(N) XOR H(g) | H(U) | s | A | B | K) let proof = { + let hn = { + let n = &self.params.n; + let mut d = D::new(); + d.input(n.to_bytes_be()); + BigUint::from_bytes_be(&d.result()) + }; + let hg = { + let g = &self.params.g; + let mut d = D::new(); + d.input(g.to_bytes_be()); + BigUint::from_bytes_be(&d.result()) + }; + let hu = { + let mut d = D::new(); + d.input(username); + d.result() + }; let mut d = D::new(); + d.input((hn ^ hg).to_bytes_be()); + d.input(hu); + d.input(salt); d.input(&self.a_pub.to_bytes_be()); d.input(&b_pub.to_bytes_be()); d.input(&key); diff --git a/srp/src/server.rs b/srp/src/server.rs index a4764d3..adc9fc5 100644 --- a/srp/src/server.rs +++ b/srp/src/server.rs @@ -52,7 +52,8 @@ pub struct UserRecord<'a> { } /// SRP server state -pub struct SrpServer { +pub struct SrpServer<'a, D: Digest> { + user: &'a UserRecord<'a>, b: BigUint, a_pub: BigUint, b_pub: BigUint, @@ -60,15 +61,17 @@ pub struct SrpServer { key: GenericArray, d: PhantomData, + + params: &'a SrpGroup, } -impl SrpServer { +impl<'a, D: Digest> SrpServer<'a, D> { /// Create new server state. pub fn new( - user: &UserRecord<'_>, + user: &'a UserRecord, a_pub: &[u8], b: &[u8], - params: &SrpGroup, + params: &'a SrpGroup, ) -> Result { let a_pub = BigUint::from_bytes_be(a_pub); // Safeguard against malicious A @@ -99,11 +102,13 @@ impl SrpServer { D::digest(&s.to_bytes_be()) }; Ok(Self { + user, b, a_pub, b_pub, key, d, + params, }) } @@ -129,13 +134,36 @@ impl SrpServer { &self, user_proof: &[u8], ) -> Result, SrpAuthError> { - // M = H(A, B, K) - let mut d = D::new(); - d.input(&self.a_pub.to_bytes_be()); - d.input(&self.b_pub.to_bytes_be()); - d.input(&self.key); + // M = H(H(N) XOR H(g) | H(U) | s | A | B | K) + let proof = { + let hn = { + let n = &self.params.n; + let mut d = D::new(); + d.input(n.to_bytes_be()); + BigUint::from_bytes_be(&d.result()) + }; + let hg = { + let g = &self.params.g; + let mut d = D::new(); + d.input(g.to_bytes_be()); + BigUint::from_bytes_be(&d.result()) + }; + let hu = { + let mut d = D::new(); + d.input(self.user.username); + d.result() + }; + let mut d = D::new(); + d.input((hn ^ hg).to_bytes_be()); + d.input(hu); + d.input(self.user.salt); + d.input(&self.a_pub.to_bytes_be()); + d.input(&self.b_pub.to_bytes_be()); + d.input(&self.key);; + d.result() + }; - if user_proof == d.result().as_slice() { + if user_proof == proof.as_slice() { // H(A, M, K) let mut d = D::new(); d.input(&self.a_pub.to_bytes_be()); diff --git a/srp/tests/mod.rs b/srp/tests/mod.rs index 58bfa0f..134c7ba 100644 --- a/srp/tests/mod.rs +++ b/srp/tests/mod.rs @@ -37,7 +37,9 @@ fn auth_test(reg_pwd: &[u8], auth_pwd: &[u8]) { // Client processes handshake reply let auth_priv_key = srp_private_key::(username, auth_pwd, salt); - let client2 = client.process_reply(&auth_priv_key, &b_pub).unwrap(); + let client2 = client + .process_reply(user.username, user.salt, &auth_priv_key, &b_pub) + .unwrap(); let proof = client2.get_proof(); // Server processes verification data From 415dae53753aa0ec48608aa62ea6bba6a1371cad Mon Sep 17 00:00:00 2001 From: Brenden Matthews Date: Tue, 13 Aug 2019 16:17:43 -0400 Subject: [PATCH 2/2] Remove extra semicolon. --- srp/src/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srp/src/server.rs b/srp/src/server.rs index adc9fc5..8e3aa52 100644 --- a/srp/src/server.rs +++ b/srp/src/server.rs @@ -159,7 +159,7 @@ impl<'a, D: Digest> SrpServer<'a, D> { d.input(self.user.salt); d.input(&self.a_pub.to_bytes_be()); d.input(&self.b_pub.to_bytes_be()); - d.input(&self.key);; + d.input(&self.key); d.result() };