From: Masih Yeganeh Date: Wed, 7 Oct 2020 19:15:18 +0000 (+0330) Subject: Bump digest, sha-1, and sha2 dependencies to v0.9 (#37) X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=00d7d43e619a6bebe17459e620edd2d123c84bcf;p=PAKEs.git Bump digest, sha-1, and sha2 dependencies to v0.9 (#37) --- diff --git a/srp/Cargo.toml b/srp/Cargo.toml index 1599447..5541039 100644 --- a/srp/Cargo.toml +++ b/srp/Cargo.toml @@ -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" } 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", diff --git a/srp/src/server.rs b/srp/src/server.rs index f30608a..9be1948 100644 --- a/srp/src/server.rs +++ b/srp/src/server.rs @@ -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 { a_pub: BigUint, b_pub: BigUint, - key: GenericArray, + key: Output, d: PhantomData, } @@ -86,14 +85,14 @@ impl SrpServer { // 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, ¶ms.n)) % ¶ms.n; let s = powm(&t, &b, ¶ms.n); D::digest(&s.to_bytes_be()) @@ -119,29 +118,26 @@ impl SrpServer { /// Get shared secret between user and the server. (do not forget to verify /// that keys are the same!) - pub fn get_key(&self) -> GenericArray { + pub fn get_key(&self) -> Output { 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, SrpAuthError> { + pub fn verify(&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); + 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", diff --git a/srp/src/types.rs b/srp/src/types.rs index 5dca858..de5958a 100644 --- a/srp/src/types.rs +++ b/srp/src/types.rs @@ -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(&self) -> Vec { + 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() } }