Adding password hashing functionality
This commit is contained in:
@@ -26,6 +26,8 @@ pub enum InternalPakeError {
|
||||
HkdfError,
|
||||
#[error("Computing HMAC failed while supplying a secret key")]
|
||||
HmacError,
|
||||
#[error("Computing the slow hashing function failed")]
|
||||
SlowHashError,
|
||||
}
|
||||
|
||||
/// Represents an error in password checking
|
||||
|
||||
+60
-23
@@ -18,8 +18,12 @@
|
||||
//! use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! use opaque_ke::keypair::X25519KeyPair;
|
||||
//! use opaque_ke::slow_hash::NoOpHash;
|
||||
//! ```
|
||||
//!
|
||||
//! Note that our choice of slow hashing function in this example, `NoOpHash`, is selected only to ensure
|
||||
//! that the tests execute quickly. A real application should use an actual slow hashing function, such as `Scrypt`.
|
||||
//!
|
||||
//! This implementation is in sync with [draft-krawczyk-cfrg-opaque-05](https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-05),
|
||||
//! with a concrete instantiation of the authenticated key exchange protocol using 3DH. In the future, we plan to
|
||||
//! add support for other KE protocols as well.
|
||||
@@ -48,8 +52,12 @@
|
||||
//! In the first step (client registration start), the client chooses a registration password and an optional "pepper", and
|
||||
//! runs `ClientRegistration::start` to produce a message `r1`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! use rand_core::{OsRng, RngCore};
|
||||
@@ -67,8 +75,12 @@
|
||||
//! In the second step (server registration start), the server takes as input the `r1` message from the client and runs
|
||||
//! `ServerRegistration::start` to produce `r2`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! # use rand_core::{OsRng, RngCore};
|
||||
@@ -93,8 +105,12 @@
|
||||
//! with the server's static public key `server_kp.public()`, and uses `client_state` from the first step to run
|
||||
//! `finish` and produce a message `r3` along with the key derivation key `kd_key_registration`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! # use rand_core::{OsRng, RngCore};
|
||||
@@ -112,7 +128,7 @@
|
||||
//! # )?;
|
||||
//! # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
|
||||
//! let (r3, kd_key_registration) =
|
||||
//! client_state.finish::<_, X25519KeyPair>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! client_state.finish::<_, X25519KeyPair, NoOpHash>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # Ok::<(), ProtocolError>(())
|
||||
//! ```
|
||||
//! `r3` is sent to the server, and the client can optionally use `kd_key_registration` for applications that choose to
|
||||
@@ -121,8 +137,12 @@
|
||||
//! In the fourth step of registration, the server takes as input the `r3` message from the client and uses
|
||||
//! `server_state` from the second step to run `finish` and produce `password_file`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! # use rand_core::{OsRng, RngCore};
|
||||
@@ -140,7 +160,7 @@
|
||||
//! # )?;
|
||||
//! # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
|
||||
//! # let (r3, kd_key_registration) =
|
||||
//! # client_state.finish::<_, X25519KeyPair>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # client_state.finish::<_, X25519KeyPair, NoOpHash>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! let password_file = server_state.finish(r3)?;
|
||||
//! # Ok::<(), ProtocolError>(())
|
||||
//! ```
|
||||
@@ -158,8 +178,12 @@
|
||||
//! In the first step (client login start), the client chooses a registration password and an optional "pepper", and runs
|
||||
//! `ClientLogin::start` to produce a message `l1`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! # use rand_core::{OsRng, RngCore};
|
||||
@@ -177,8 +201,12 @@
|
||||
//! private key `server_kp.private()`, along with a serialized version of the password file, `password_file_bytes`, and
|
||||
//! runs `ServerLogin::start` to produce `l2`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! # use rand_core::{OsRng, RngCore};
|
||||
@@ -196,7 +224,7 @@
|
||||
//! # )?;
|
||||
//! # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
|
||||
//! # let (r3, kd_key_registration) =
|
||||
//! # client_state.finish::<_, X25519KeyPair>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # client_state.finish::<_, X25519KeyPair, NoOpHash>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
|
||||
//! # let (l1, client_state) = ClientLogin::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(
|
||||
//! # b"password",
|
||||
@@ -219,8 +247,12 @@
|
||||
//! server's static public key `server_kp.public()`, and uses `client_state` from the first step to run `finish` and produce
|
||||
//! a message `l3`, the shared secret `client_shared_secret`, and the key derivation key `kd_key_login`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! # use rand_core::{OsRng, RngCore};
|
||||
@@ -238,7 +270,7 @@
|
||||
//! # )?;
|
||||
//! # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
|
||||
//! # let (r3, kd_key_registration) =
|
||||
//! # client_state.finish::<_, X25519KeyPair>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # client_state.finish::<_, X25519KeyPair, NoOpHash>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
|
||||
//! # let (l1, client_state) = ClientLogin::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(
|
||||
//! # b"password",
|
||||
@@ -252,7 +284,7 @@
|
||||
//! # )?;
|
||||
//! # let (l2, server_state) =
|
||||
//! # ServerLogin::start(password_file, &server_kp.private(), l1, &mut server_rng)?;
|
||||
//! let (l3, client_shared_secret, kd_key_login) = client_state.finish(
|
||||
//! let (l3, client_shared_secret, kd_key_login) = client_state.finish::<_, NoOpHash>(
|
||||
//! l2,
|
||||
//! &server_kp.public(),
|
||||
//! &mut client_rng,
|
||||
@@ -270,8 +302,12 @@
|
||||
//! In the fourth step of login, the server takes as input the `l3` message from the client and uses `server_state` from
|
||||
//! the second step to run `finish`:
|
||||
//! ```
|
||||
//! # use opaque_ke::{opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage}, keypair::{KeyPair, X25519KeyPair, SizedBytes}};
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage},
|
||||
//! # keypair::{KeyPair, X25519KeyPair, SizedBytes},
|
||||
//! # slow_hash::NoOpHash,
|
||||
//! # };
|
||||
//! # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
//! # use chacha20poly1305::ChaCha20Poly1305;
|
||||
//! # use rand_core::{OsRng, RngCore};
|
||||
@@ -289,7 +325,7 @@
|
||||
//! # )?;
|
||||
//! # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
|
||||
//! # let (r3, kd_key) =
|
||||
//! # client_state.finish::<_, X25519KeyPair>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # client_state.finish::<_, X25519KeyPair, NoOpHash>(r2, server_kp.public(), &mut client_rng)?;
|
||||
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
|
||||
//! # let (l1, client_state) = ClientLogin::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(
|
||||
//! # b"password",
|
||||
@@ -303,7 +339,7 @@
|
||||
//! # )?;
|
||||
//! # let (l2, server_state) =
|
||||
//! # ServerLogin::start(password_file, &server_kp.private(), l1, &mut server_rng)?;
|
||||
//! # let (l3, client_shared_secret, kd_key) = client_state.finish(
|
||||
//! # let (l3, client_shared_secret, kd_key) = client_state.finish::<_, NoOpHash>(
|
||||
//! # l2,
|
||||
//! # &server_kp.public(),
|
||||
//! # &mut client_rng,
|
||||
@@ -331,6 +367,7 @@ mod oprf;
|
||||
// Technical module for your choice of cyclic subgroup to
|
||||
// do the oprf on
|
||||
mod group;
|
||||
pub mod slow_hash;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
+29
-16
@@ -16,6 +16,7 @@ use crate::{
|
||||
oprf,
|
||||
oprf::OprfClientBytes,
|
||||
rkr_encryption::{RKRCipher, RKRCiphertext},
|
||||
slow_hash::SlowHash,
|
||||
};
|
||||
use generic_array::{
|
||||
typenum::{Unsigned, U32, U64},
|
||||
@@ -363,6 +364,7 @@ where
|
||||
/// use opaque_ke::{opaque::{ClientRegistration, ServerRegistration}, keypair::{X25519KeyPair, SizedBytes}};
|
||||
/// # use opaque_ke::errors::ProtocolError;
|
||||
/// # use opaque_ke::keypair::KeyPair;
|
||||
/// # use opaque_ke::slow_hash::NoOpHash;
|
||||
/// use rand_core::{OsRng, RngCore};
|
||||
/// use chacha20poly1305::ChaCha20Poly1305;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
@@ -373,10 +375,10 @@ where
|
||||
/// let (register_m2, server_state) =
|
||||
/// ServerRegistration::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(register_m1, &mut server_rng)?;
|
||||
/// let mut client_rng = OsRng;
|
||||
/// let register_m3 = client_state.finish::<_, X25519KeyPair>(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// let register_m3 = client_state.finish::<_, X25519KeyPair, NoOpHash>(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// # Ok::<(), ProtocolError>(())
|
||||
/// ```
|
||||
pub fn finish<R: CryptoRng + RngCore, KeyFormat: KeyPair>(
|
||||
pub fn finish<R: CryptoRng + RngCore, KeyFormat: KeyPair, SH: SlowHash>(
|
||||
self,
|
||||
r2: RegisterSecondMessage<Grp>,
|
||||
server_s_pk: &KeyFormat::Repr,
|
||||
@@ -384,8 +386,11 @@ where
|
||||
) -> Result<ClientRegistrationFinishResult<Aead, KeyFormat>, ProtocolError> {
|
||||
let client_static_keypair = KeyFormat::generate_random(rng)?;
|
||||
|
||||
let password_derived_key =
|
||||
get_password_derived_key::<Grp>(self.password.clone(), r2.beta, &self.blinding_factor)?;
|
||||
let password_derived_key = get_password_derived_key::<Grp, SH>(
|
||||
self.password.clone(),
|
||||
r2.beta,
|
||||
&self.blinding_factor,
|
||||
)?;
|
||||
let h = Hkdf::<Sha256>::new(None, &password_derived_key);
|
||||
let mut okm = [0u8; 3 * DERIVED_KEY_LEN];
|
||||
h.expand(STR_ENVU, &mut okm)
|
||||
@@ -572,6 +577,7 @@ where
|
||||
/// use opaque_ke::{opaque::*, keypair::{X25519KeyPair, SizedBytes}};
|
||||
/// # use opaque_ke::errors::ProtocolError;
|
||||
/// # use opaque_ke::keypair::KeyPair;
|
||||
/// # use opaque_ke::slow_hash::NoOpHash;
|
||||
/// use rand_core::{OsRng, RngCore};
|
||||
/// use chacha20poly1305::ChaCha20Poly1305;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
@@ -582,7 +588,7 @@ where
|
||||
/// let (register_m2, server_state) =
|
||||
/// ServerRegistration::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(register_m1, &mut server_rng)?;
|
||||
/// let mut client_rng = OsRng;
|
||||
/// let (register_m3, _opaque_key) = client_state.finish(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// let (register_m3, _opaque_key) = client_state.finish::<_, _, NoOpHash>(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// let client_record = server_state.finish(register_m3)?;
|
||||
/// # Ok::<(), ProtocolError>(())
|
||||
/// ```
|
||||
@@ -722,6 +728,7 @@ where
|
||||
/// # use opaque_ke::opaque::{ClientRegistration, ServerRegistration};
|
||||
/// # use opaque_ke::errors::ProtocolError;
|
||||
/// # use opaque_ke::keypair::{X25519KeyPair, KeyPair};
|
||||
/// # use opaque_ke::slow_hash::NoOpHash;
|
||||
/// use rand_core::{OsRng, RngCore};
|
||||
/// use chacha20poly1305::ChaCha20Poly1305;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
@@ -730,14 +737,14 @@ where
|
||||
/// # let (register_m1, client_state) = ClientRegistration::<ChaCha20Poly1305, RistrettoPoint>::start(b"hunter2", None, &mut client_rng)?;
|
||||
/// # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
|
||||
/// # let (register_m2, server_state) = ServerRegistration::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(register_m1, &mut server_rng)?;
|
||||
/// # let (register_m3, _opaque_key) = client_state.finish(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// # let (register_m3, _opaque_key) = client_state.finish::<_, _, NoOpHash>(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// # let p_file = server_state.finish(register_m3)?;
|
||||
/// let (login_m1, client_login_state) = ClientLogin::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(b"hunter2", None, &mut client_rng)?;
|
||||
/// let (login_m2, server_login_state) = ServerLogin::start(p_file, &server_kp.private(), login_m1, &mut server_rng)?;
|
||||
/// let (login_m3, client_transport, _opaque_key) = client_login_state.finish(login_m2, &server_kp.public(), &mut client_rng)?;
|
||||
/// let (login_m3, client_transport, _opaque_key) = client_login_state.finish::<_, NoOpHash>(login_m2, &server_kp.public(), &mut client_rng)?;
|
||||
/// # Ok::<(), ProtocolError>(())
|
||||
/// ```
|
||||
pub fn finish<R: RngCore + CryptoRng>(
|
||||
pub fn finish<R: RngCore + CryptoRng, SH: SlowHash>(
|
||||
self,
|
||||
l2: LoginSecondMessage<Aead, Grp>,
|
||||
server_s_pk: &KeyFormat::Repr,
|
||||
@@ -745,8 +752,11 @@ where
|
||||
) -> Result<ClientLoginFinishResult, ProtocolError> {
|
||||
let l2_bytes: Vec<u8> = [l2.beta.to_bytes().as_slice(), &l2.envelope.to_bytes()].concat();
|
||||
|
||||
let password_derived_key =
|
||||
get_password_derived_key::<Grp>(self.password.clone(), l2.beta, &self.blinding_factor)?;
|
||||
let password_derived_key = get_password_derived_key::<Grp, SH>(
|
||||
self.password.clone(),
|
||||
l2.beta,
|
||||
&self.blinding_factor,
|
||||
)?;
|
||||
let h = Hkdf::<Sha256>::new(None, &password_derived_key);
|
||||
let mut okm = [0u8; 3 * DERIVED_KEY_LEN];
|
||||
h.expand(STR_ENVU, &mut okm)
|
||||
@@ -812,6 +822,7 @@ impl ServerLogin {
|
||||
/// # use opaque_ke::opaque::{ClientRegistration, ServerRegistration};
|
||||
/// # use opaque_ke::errors::ProtocolError;
|
||||
/// # use opaque_ke::keypair::{KeyPair, X25519KeyPair};
|
||||
/// # use opaque_ke::slow_hash::NoOpHash;
|
||||
/// use rand_core::{OsRng, RngCore};
|
||||
/// use chacha20poly1305::ChaCha20Poly1305;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
@@ -821,7 +832,7 @@ impl ServerLogin {
|
||||
/// # let (register_m1, client_state) = ClientRegistration::<ChaCha20Poly1305, RistrettoPoint>::start(b"hunter2", None, &mut client_rng)?;
|
||||
/// # let (register_m2, server_state) =
|
||||
/// ServerRegistration::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(register_m1, &mut server_rng)?;
|
||||
/// # let (register_m3, _opaque_key) = client_state.finish(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// # let (register_m3, _opaque_key) = client_state.finish::<_, _, NoOpHash>(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// # let p_file = server_state.finish(register_m3)?;
|
||||
/// let (login_m1, client_login_state) = ClientLogin::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(b"hunter2", None, &mut client_rng)?;
|
||||
/// let (login_m2, server_login_state) = ServerLogin::start(p_file, &server_kp.private(), login_m1, &mut server_rng)?;
|
||||
@@ -880,6 +891,7 @@ impl ServerLogin {
|
||||
/// # use opaque_ke::opaque::{ClientRegistration, ServerRegistration};
|
||||
/// # use opaque_ke::errors::ProtocolError;
|
||||
/// # use opaque_ke::keypair::{KeyPair, X25519KeyPair};
|
||||
/// # use opaque_ke::slow_hash::NoOpHash;
|
||||
/// use rand_core::{OsRng, RngCore};
|
||||
/// use chacha20poly1305::ChaCha20Poly1305;
|
||||
/// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
@@ -889,11 +901,11 @@ impl ServerLogin {
|
||||
/// # let (register_m1, client_state) = ClientRegistration::<ChaCha20Poly1305, RistrettoPoint>::start(b"hunter2", None, &mut client_rng)?;
|
||||
/// # let (register_m2, server_state) =
|
||||
/// ServerRegistration::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(register_m1, &mut server_rng)?;
|
||||
/// # let (register_m3, _opaque_key) = client_state.finish(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// # let (register_m3, _opaque_key) = client_state.finish::<_, _, NoOpHash>(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
/// # let p_file = server_state.finish(register_m3)?;
|
||||
/// let (login_m1, client_login_state) = ClientLogin::<ChaCha20Poly1305, RistrettoPoint, X25519KeyPair>::start(b"hunter2", None, &mut client_rng)?;
|
||||
/// let (login_m2, server_login_state) = ServerLogin::start(p_file, &server_kp.private(), login_m1, &mut server_rng)?;
|
||||
/// let (login_m3, client_transport, _opaque_key) = client_login_state.finish(login_m2, &server_kp.public(), &mut client_rng)?;
|
||||
/// let (login_m3, client_transport, _opaque_key) = client_login_state.finish::<_, NoOpHash>(login_m2, &server_kp.public(), &mut client_rng)?;
|
||||
/// let mut server_transport = server_login_state.finish(login_m3)?;
|
||||
/// # Ok::<(), ProtocolError>(())
|
||||
/// ```
|
||||
@@ -909,10 +921,11 @@ impl ServerLogin {
|
||||
|
||||
// Helper functions
|
||||
|
||||
fn get_password_derived_key<G: Group>(
|
||||
fn get_password_derived_key<G: Group, SH: SlowHash>(
|
||||
password: Vec<u8>,
|
||||
beta: G,
|
||||
blinding_factor: &G::Scalar,
|
||||
) -> Result<GenericArray<u8, <Sha256 as Digest>::OutputSize>, PakeError> {
|
||||
Ok(oprf::generate_oprf3::<G>(&password, beta, blinding_factor)?)
|
||||
) -> Result<Vec<u8>, InternalPakeError> {
|
||||
let oprf_output = oprf::generate_oprf3::<G>(&password, beta, blinding_factor)?;
|
||||
SH::hash(oprf_output)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
||||
//
|
||||
// This source code is licensed under the MIT license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
use crate::errors::InternalPakeError;
|
||||
|
||||
use generic_array::GenericArray;
|
||||
use scrypt::{scrypt, ScryptParams};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
pub trait SlowHash {
|
||||
fn hash(
|
||||
input: GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
||||
) -> Result<Vec<u8>, InternalPakeError>;
|
||||
}
|
||||
|
||||
pub struct NoOpHash;
|
||||
|
||||
impl SlowHash for NoOpHash {
|
||||
fn hash(
|
||||
input: GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
||||
) -> Result<Vec<u8>, InternalPakeError> {
|
||||
Ok(input.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Scrypt;
|
||||
|
||||
impl SlowHash for Scrypt {
|
||||
fn hash(
|
||||
input: GenericArray<u8, <Sha256 as Digest>::OutputSize>,
|
||||
) -> Result<Vec<u8>, InternalPakeError> {
|
||||
let params = ScryptParams::new(15, 8, 1).unwrap();
|
||||
let mut output = [0u8; 32];
|
||||
scrypt(&input, &[], ¶ms, &mut output).map_err(|_| InternalPakeError::SlowHashError)?;
|
||||
Ok(output.to_vec())
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use crate::{
|
||||
key_exchange::NONCE_LEN,
|
||||
keypair::{Key, KeyPair, SignalKeyPair},
|
||||
opaque::*,
|
||||
slow_hash::NoOpHash,
|
||||
tests::mock_rng::CycleRng,
|
||||
};
|
||||
use aes_gcm::Aes256Gcm;
|
||||
@@ -257,7 +258,11 @@ fn generate_parameters() -> TestVectorParameters {
|
||||
|
||||
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
|
||||
let (r3, opaque_key_registration) = client_registration
|
||||
.finish::<_, SignalKeyPair>(r2, server_s_kp.public(), &mut finish_registration_rng)
|
||||
.finish::<_, SignalKeyPair, NoOpHash>(
|
||||
r2,
|
||||
server_s_kp.public(),
|
||||
&mut finish_registration_rng,
|
||||
)
|
||||
.unwrap();
|
||||
let r3_bytes = r3.to_bytes().to_vec();
|
||||
|
||||
@@ -292,7 +297,7 @@ fn generate_parameters() -> TestVectorParameters {
|
||||
|
||||
let mut client_e_sk_rng = CycleRng::new(client_e_kp.private().to_vec());
|
||||
let (l3, client_shared_secret, _opaque_key_login) = client_login
|
||||
.finish(l2, server_s_kp.public(), &mut client_e_sk_rng)
|
||||
.finish::<_, NoOpHash>(l2, server_s_kp.public(), &mut client_e_sk_rng)
|
||||
.unwrap();
|
||||
let l3_bytes = l3.to_bytes().to_vec();
|
||||
|
||||
@@ -382,7 +387,7 @@ fn test_r3() -> Result<(), PakeError> {
|
||||
¶meters.client_registration_state[..],
|
||||
)
|
||||
.unwrap()
|
||||
.finish::<CycleRng, SignalKeyPair>(
|
||||
.finish::<CycleRng, SignalKeyPair, NoOpHash>(
|
||||
RegisterSecondMessage::try_from(¶meters.r2[..]).unwrap(),
|
||||
&Key::try_from(parameters.server_s_pk).unwrap(),
|
||||
&mut finish_registration_rng,
|
||||
@@ -474,7 +479,7 @@ fn test_l3() -> Result<(), PakeError> {
|
||||
¶meters.client_login_state[..],
|
||||
)
|
||||
.unwrap()
|
||||
.finish(
|
||||
.finish::<_, NoOpHash>(
|
||||
LoginSecondMessage::<Aes256Gcm, EdwardsPoint>::try_from(¶meters.l2[..]).unwrap(),
|
||||
&Key::try_from(parameters.server_s_pk)?,
|
||||
&mut client_e_sk_rng,
|
||||
@@ -529,7 +534,7 @@ fn test_complete_flow(
|
||||
&mut server_rng,
|
||||
)?;
|
||||
let (register_m3, registration_opaque_key) =
|
||||
client_state.finish(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
client_state.finish::<_, _, NoOpHash>(register_m2, server_kp.public(), &mut client_rng)?;
|
||||
let p_file = server_state.finish(register_m3)?;
|
||||
let (login_m1, client_login_state) =
|
||||
ClientLogin::<Aes256Gcm, EdwardsPoint, SignalKeyPair>::start(
|
||||
@@ -541,7 +546,7 @@ fn test_complete_flow(
|
||||
ServerLogin::start(p_file, &server_kp.private(), login_m1, &mut server_rng)?;
|
||||
|
||||
let client_login_result =
|
||||
client_login_state.finish(login_m2, &server_kp.public(), &mut client_rng);
|
||||
client_login_state.finish::<_, NoOpHash>(login_m2, &server_kp.public(), &mut client_rng);
|
||||
|
||||
if hex::encode(registration_password) == hex::encode(login_password) {
|
||||
let (login_m3, client_shared_secret, login_opaque_key) = client_login_result?;
|
||||
|
||||
Reference in New Issue
Block a user