]> git.lizzy.rs Git - PAKEs.git/commitdiff
Bump digest, sha-1, and sha2 dependencies to v0.9 (#37)
authorMasih Yeganeh <goodboy.php@gmail.com>
Wed, 7 Oct 2020 19:15:18 +0000 (22:45 +0330)
committerGitHub <noreply@github.com>
Wed, 7 Oct 2020 19:15:18 +0000 (12:15 -0700)
srp/Cargo.toml
srp/src/client.rs
srp/src/server.rs
srp/src/types.rs

index 15994476363b06913724180dd4ff1b1f67a3b94b..5541039ffc13c870bb88ca32e5ac56698a866ab0 100644 (file)
@@ -13,13 +13,13 @@ categories = ["cryptography", "authentication"]
 [dependencies]
 num-bigint = "0.2"
 generic-array = "0.12"
-digest = "0.8"
+digest = "0.9"
 lazy_static = "1.2"
 
 [dev-dependencies]
 rand = "0.6"
-sha2 = "0.8"
-sha-1 = "0.8"
+sha2 = "0.9"
+sha-1 = "0.9"
 
 [badges]
 travis-ci = { repository = "RustCrypto/PAKEs" }
index a33f9b39dc1f36e847faebfd3954c62fbbbc0286..a9f7564d5831489151270de884d35a0efc6f922d 100644 (file)
@@ -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<D: Digest> {
-    proof: GenericArray<u8, D::OutputSize>,
-    server_proof: GenericArray<u8, D::OutputSize>,
-    key: GenericArray<u8, D::OutputSize>,
+    proof: Output<D>,
+    server_proof: Output<D>,
+    key: Output<D>,
 }
 
 /// Compute user private key as described in the RFC 5054. Consider using proper
 /// password hashing algorithm instead.
-pub fn srp_private_key<D: Digest>(
-    username: &[u8],
-    password: &[u8],
-    salt: &[u8],
-) -> GenericArray<u8, D::OutputSize> {
+pub fn srp_private_key<D: Digest>(username: &[u8], password: &[u8], salt: &[u8]) -> Output<D> {
     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<u8, D::OutputSize> {
+    fn calc_key(&self, b_pub: &BigUint, x: &BigUint, u: &BigUint) -> Output<D> {
         let n = &self.params.n;
         let k = self.params.compute_k::<D>();
         let interm = (k * self.params.powm(x)) % n;
@@ -151,9 +141,10 @@ impl<'a, D: Digest> SrpClient<'a, D> {
     ) -> Result<SrpClientVerifier<D>, 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<SrpClientVerifier<D>, 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>());
+            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<D: Digest> SrpClientVerifier<D> {
     /// 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<u8, D::OutputSize> {
+    pub fn get_key(self) -> Output<D> {
         self.key
     }
 
     /// Verification data for sending to the server.
-    pub fn get_proof(&self) -> GenericArray<u8, D::OutputSize> {
+    pub fn get_proof(&self) -> Output<D> {
         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<GenericArray<u8, D::OutputSize>, SrpAuthError> {
+    pub fn verify_server(self, reply: &[u8]) -> Result<Output<D>, SrpAuthError> {
         if self.server_proof.as_slice() != reply {
             Err(SrpAuthError {
                 description: "Incorrect server proof",
index f30608a34c2850bc0bcc23cb618f783684468d87..9be1948ecef147fdabb5443f7ccb379de92f6029 100644 (file)
@@ -36,8 +36,7 @@
 //! encryption.
 use std::marker::PhantomData;
 
-use digest::Digest;
-use generic_array::GenericArray;
+use digest::{Digest, Output};
 use num_bigint::BigUint;
 
 use crate::tools::powm;
@@ -57,7 +56,7 @@ pub struct SrpServer<D: Digest> {
     a_pub: BigUint,
     b_pub: BigUint,
 
-    key: GenericArray<u8, D::OutputSize>,
+    key: Output<D>,
 
     d: PhantomData<D>,
 }
@@ -86,14 +85,14 @@ impl<D: Digest> SrpServer<D> {
         // H(A || B)
         let u = {
             let mut d = D::new();
-            d.input(&a_pub.to_bytes_be());
-            d.input(&b_pub.to_bytes_be());
-            d.result()
+            d.update(&a_pub.to_bytes_be());
+            d.update(&b_pub.to_bytes_be());
+            d.finalize()
         };
         let d = Default::default();
         //(Av^u) ^ b
         let key = {
-            let u = BigUint::from_bytes_be(&u);
+            let u = BigUint::from_bytes_be(u.as_slice());
             let t = (&a_pub * powm(&v, &u, &params.n)) % &params.n;
             let s = powm(&t, &b, &params.n);
             D::digest(&s.to_bytes_be())
@@ -119,29 +118,26 @@ impl<D: Digest> SrpServer<D> {
 
     /// Get shared secret between user and the server. (do not forget to verify
     /// that keys are the same!)
-    pub fn get_key(&self) -> GenericArray<u8, D::OutputSize> {
+    pub fn get_key(&self) -> Output<D> {
         self.key.clone()
     }
 
     /// Process user proof of having the same shared secret and compute
     /// server proof for sending to the user.
-    pub fn verify(
-        &self,
-        user_proof: &[u8],
-    ) -> Result<GenericArray<u8, D::OutputSize>, SrpAuthError> {
+    pub fn verify(&self, user_proof: &[u8]) -> Result<Output<D>, 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);
+        d.update(&self.a_pub.to_bytes_be());
+        d.update(&self.b_pub.to_bytes_be());
+        d.update(&self.key);
 
-        if user_proof == d.result().as_slice() {
+        if user_proof == d.finalize().as_slice() {
             // H(A, M, K)
             let mut d = D::new();
-            d.input(&self.a_pub.to_bytes_be());
-            d.input(user_proof);
-            d.input(&self.key);
-            Ok(d.result())
+            d.update(&self.a_pub.to_bytes_be());
+            d.update(user_proof);
+            d.update(&self.key);
+            Ok(d.finalize())
         } else {
             Err(SrpAuthError {
                 description: "Incorrect user proof",
index 5dca8587f68dd3dcadeda88a9a61af58c29f3556..de5958a9795bfd5449c6f542618baddffbc9ecf4 100644 (file)
@@ -45,9 +45,31 @@ impl SrpGroup {
         buf[l..].copy_from_slice(&g_bytes);
 
         let mut d = D::new();
-        d.input(&n);
-        d.input(&buf);
-        BigUint::from_bytes_be(&d.result())
+        d.update(&n);
+        d.update(&buf);
+        BigUint::from_bytes_be(&d.finalize().as_slice())
+    }
+
+    /// Compute `Hash(N) xor Hash(g)` with given hash function and return SRP parameters
+    pub(crate) fn compute_hash_n_xor_hash_g<D: Digest>(&self) -> Vec<u8> {
+        let n = self.n.to_bytes_be();
+        let g_bytes = self.g.to_bytes_be();
+        let mut buf = vec![0u8; n.len()];
+        let l = n.len() - g_bytes.len();
+        buf[l..].copy_from_slice(&g_bytes);
+
+        let mut d = D::new();
+        d.update(&n);
+        let h = d.finalize_reset();
+        let h_n: &[u8] = h.as_slice();
+        d.update(&buf);
+        let h = d.finalize_reset();
+        let h_g: &[u8] = h.as_slice();
+
+        h_n.iter()
+            .zip(h_g.iter())
+            .map(|(&x1, &x2)| x1 ^ x2)
+            .collect()
     }
 }