2021-06-08 20:23:46 +00:00
|
|
|
use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
use rand::{CryptoRng, RngCore};
|
|
|
|
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
|
|
pub enum AuthenticationError {
|
|
|
|
#[error("Protocol error: `{0}`")]
|
|
|
|
ProtocolError(#[from] opaque_ke::errors::ProtocolError),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type AuthenticationResult<T> = std::result::Result<T, AuthenticationError>;
|
|
|
|
|
2021-06-23 08:57:34 +00:00
|
|
|
pub use opaque_ke::keypair::{PrivateKey, PublicKey};
|
2021-06-15 21:07:22 +00:00
|
|
|
pub type KeyPair = opaque_ke::keypair::KeyPair<<DefaultSuite as CipherSuite>::Group>;
|
2021-06-14 14:02:36 +00:00
|
|
|
|
2021-06-08 21:24:33 +00:00
|
|
|
/// A wrapper around argon2 to provide the [`opaque_ke::slow_hash::SlowHash`] trait.
|
|
|
|
pub struct ArgonHasher;
|
|
|
|
|
2021-10-20 05:43:02 +00:00
|
|
|
/// The Argon hasher used for bruteforce protection.
|
|
|
|
///
|
|
|
|
/// Note that it isn't used to "hash the passwords", so it doesn't need a variable salt. Instead,
|
|
|
|
/// it's used as part of the OPAQUE protocol to add a slow hashing method, making bruteforce
|
|
|
|
/// attacks prohibitively more expensive.
|
2021-06-08 21:24:33 +00:00
|
|
|
impl ArgonHasher {
|
|
|
|
/// Fixed salt, doesn't affect the security. It is only used to make attacks more
|
|
|
|
/// computationally intensive, it doesn't serve any security purpose.
|
|
|
|
const SALT: &'static [u8] = b"lldap_opaque_salt";
|
|
|
|
/// Config for the argon hasher. Security enthusiasts may want to tweak this for their system.
|
|
|
|
const CONFIG: &'static argon2::Config<'static> = &argon2::Config {
|
|
|
|
ad: &[],
|
|
|
|
hash_length: 128,
|
|
|
|
lanes: 1,
|
|
|
|
mem_cost: 50 * 1024, // 50 MB, in KB
|
|
|
|
secret: &[],
|
|
|
|
thread_mode: argon2::ThreadMode::Sequential,
|
2021-10-11 18:09:34 +00:00
|
|
|
time_cost: 1,
|
2021-06-08 21:24:33 +00:00
|
|
|
variant: argon2::Variant::Argon2id,
|
|
|
|
version: argon2::Version::Version13,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<D: opaque_ke::hash::Hash> opaque_ke::slow_hash::SlowHash<D> for ArgonHasher {
|
|
|
|
fn hash(
|
|
|
|
input: generic_array::GenericArray<u8, <D as digest::Digest>::OutputSize>,
|
|
|
|
) -> Result<Vec<u8>, opaque_ke::errors::InternalPakeError> {
|
|
|
|
argon2::hash_raw(&input, Self::SALT, Self::CONFIG)
|
|
|
|
.map_err(|_| opaque_ke::errors::InternalPakeError::HashingFailure)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-08 20:23:46 +00:00
|
|
|
/// The ciphersuite trait allows to specify the underlying primitives
|
|
|
|
/// that will be used in the OPAQUE protocol
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub struct DefaultSuite;
|
|
|
|
impl CipherSuite for DefaultSuite {
|
|
|
|
type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
|
|
|
type Hash = sha2::Sha512;
|
2021-06-08 21:24:33 +00:00
|
|
|
/// Use argon2 as the slow hashing algorithm for our CipherSuite.
|
|
|
|
type SlowHash = ArgonHasher;
|
2021-06-08 20:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Client-side code for OPAQUE protocol handling, to register a new user and login. All methods'
|
|
|
|
/// results must be sent to the server using the serialized `.message`. Incoming messages can be
|
|
|
|
/// deserialized using the type's `deserialize` method.
|
|
|
|
#[cfg(feature = "opaque_client")]
|
|
|
|
pub mod client {
|
2021-06-14 14:02:36 +00:00
|
|
|
pub use super::*;
|
2021-06-08 20:23:46 +00:00
|
|
|
/// Methods to register a new user, from the client side.
|
|
|
|
pub mod registration {
|
2021-06-14 14:02:36 +00:00
|
|
|
pub use super::*;
|
2021-06-15 08:12:41 +00:00
|
|
|
pub type ClientRegistration = opaque_ke::ClientRegistration<DefaultSuite>;
|
2021-06-23 08:57:34 +00:00
|
|
|
pub type ClientRegistrationStartResult =
|
|
|
|
opaque_ke::ClientRegistrationStartResult<DefaultSuite>;
|
|
|
|
pub type ClientRegistrationFinishResult =
|
|
|
|
opaque_ke::ClientRegistrationFinishResult<DefaultSuite>;
|
2021-06-15 08:12:41 +00:00
|
|
|
pub type RegistrationResponse = opaque_ke::RegistrationResponse<DefaultSuite>;
|
|
|
|
pub use opaque_ke::ClientRegistrationFinishParameters;
|
2021-06-08 20:23:46 +00:00
|
|
|
/// Initiate the registration negotiation.
|
|
|
|
pub fn start_registration<R: RngCore + CryptoRng>(
|
|
|
|
password: &str,
|
|
|
|
rng: &mut R,
|
2021-06-15 08:12:41 +00:00
|
|
|
) -> AuthenticationResult<ClientRegistrationStartResult> {
|
2021-06-23 08:57:34 +00:00
|
|
|
Ok(ClientRegistration::start(rng, password.as_bytes())?)
|
2021-06-08 20:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Finalize the registration negotiation.
|
|
|
|
pub fn finish_registration<R: RngCore + CryptoRng>(
|
2021-06-15 08:12:41 +00:00
|
|
|
registration_start: ClientRegistration,
|
|
|
|
registration_response: RegistrationResponse,
|
2021-06-08 20:23:46 +00:00
|
|
|
rng: &mut R,
|
2021-06-15 08:12:41 +00:00
|
|
|
) -> AuthenticationResult<ClientRegistrationFinishResult> {
|
2021-06-08 20:23:46 +00:00
|
|
|
Ok(registration_start.finish(
|
|
|
|
rng,
|
|
|
|
registration_response,
|
|
|
|
ClientRegistrationFinishParameters::default(),
|
|
|
|
)?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Methods to login, from the client side.
|
|
|
|
pub mod login {
|
2021-06-14 14:02:36 +00:00
|
|
|
pub use super::*;
|
2021-06-15 08:12:41 +00:00
|
|
|
pub type ClientLogin = opaque_ke::ClientLogin<DefaultSuite>;
|
|
|
|
pub type ClientLoginFinishResult = opaque_ke::ClientLoginFinishResult<DefaultSuite>;
|
|
|
|
pub type ClientLoginStartResult = opaque_ke::ClientLoginStartResult<DefaultSuite>;
|
|
|
|
pub type CredentialResponse = opaque_ke::CredentialResponse<DefaultSuite>;
|
2021-06-16 17:12:41 +00:00
|
|
|
pub type CredentialFinalization = opaque_ke::CredentialFinalization<DefaultSuite>;
|
2021-06-23 18:33:36 +00:00
|
|
|
pub use opaque_ke::ClientLoginFinishParameters;
|
2021-06-08 20:23:46 +00:00
|
|
|
|
|
|
|
/// Initiate the login negotiation.
|
|
|
|
pub fn start_login<R: RngCore + CryptoRng>(
|
|
|
|
password: &str,
|
|
|
|
rng: &mut R,
|
2021-06-15 08:12:41 +00:00
|
|
|
) -> AuthenticationResult<ClientLoginStartResult> {
|
2021-06-23 18:33:36 +00:00
|
|
|
Ok(ClientLogin::start(rng, password.as_bytes())?)
|
2021-06-08 20:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Finalize the client login negotiation.
|
|
|
|
pub fn finish_login(
|
2021-06-15 08:12:41 +00:00
|
|
|
login_start: ClientLogin,
|
|
|
|
login_response: CredentialResponse,
|
|
|
|
) -> AuthenticationResult<ClientLoginFinishResult> {
|
2021-06-08 20:23:46 +00:00
|
|
|
Ok(login_start.finish(login_response, ClientLoginFinishParameters::default())?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Server-side code for OPAQUE protocol handling, to register a new user and login. The
|
|
|
|
/// intermediate results must be sent to the client using the serialized `.message`.
|
|
|
|
#[cfg(feature = "opaque_server")]
|
|
|
|
pub mod server {
|
2021-06-14 14:02:36 +00:00
|
|
|
pub use super::*;
|
2021-06-15 08:12:41 +00:00
|
|
|
pub type ServerRegistration = opaque_ke::ServerRegistration<DefaultSuite>;
|
2021-06-23 18:33:36 +00:00
|
|
|
pub type ServerSetup = opaque_ke::ServerSetup<DefaultSuite>;
|
2021-06-08 20:23:46 +00:00
|
|
|
/// Methods to register a new user, from the server side.
|
|
|
|
pub mod registration {
|
2021-06-14 14:02:36 +00:00
|
|
|
pub use super::*;
|
2021-06-15 08:12:41 +00:00
|
|
|
pub type RegistrationRequest = opaque_ke::RegistrationRequest<DefaultSuite>;
|
|
|
|
pub type RegistrationUpload = opaque_ke::RegistrationUpload<DefaultSuite>;
|
2021-06-23 08:57:34 +00:00
|
|
|
pub type ServerRegistrationStartResult =
|
|
|
|
opaque_ke::ServerRegistrationStartResult<DefaultSuite>;
|
2021-06-08 20:23:46 +00:00
|
|
|
/// Start a registration process, from a request sent by the client.
|
|
|
|
///
|
|
|
|
/// The result must be kept for the next step.
|
2021-06-23 18:33:36 +00:00
|
|
|
pub fn start_registration(
|
|
|
|
server_setup: &ServerSetup,
|
2021-06-15 08:12:41 +00:00
|
|
|
registration_request: RegistrationRequest,
|
2021-06-23 18:33:36 +00:00
|
|
|
username: &str,
|
2021-06-15 08:12:41 +00:00
|
|
|
) -> AuthenticationResult<ServerRegistrationStartResult> {
|
|
|
|
Ok(ServerRegistration::start(
|
2021-06-23 18:33:36 +00:00
|
|
|
server_setup,
|
2021-06-08 20:23:46 +00:00
|
|
|
registration_request,
|
2021-06-23 18:33:36 +00:00
|
|
|
username.as_bytes(),
|
2021-06-08 20:23:46 +00:00
|
|
|
)?)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Finish to register a new user, and get the data to store in the database.
|
2021-06-23 18:33:36 +00:00
|
|
|
pub fn get_password_file(registration_upload: RegistrationUpload) -> ServerRegistration {
|
|
|
|
ServerRegistration::finish(registration_upload)
|
2021-06-08 20:23:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Methods to handle user login, from the server-side.
|
|
|
|
pub mod login {
|
2021-06-14 14:02:36 +00:00
|
|
|
pub use super::*;
|
2021-06-15 08:12:41 +00:00
|
|
|
pub type CredentialFinalization = opaque_ke::CredentialFinalization<DefaultSuite>;
|
|
|
|
pub type CredentialRequest = opaque_ke::CredentialRequest<DefaultSuite>;
|
|
|
|
pub type ServerLogin = opaque_ke::ServerLogin<DefaultSuite>;
|
|
|
|
pub type ServerLoginStartResult = opaque_ke::ServerLoginStartResult<DefaultSuite>;
|
|
|
|
pub type ServerLoginFinishResult = opaque_ke::ServerLoginFinishResult<DefaultSuite>;
|
|
|
|
pub use opaque_ke::ServerLoginStartParameters;
|
2021-06-08 20:23:46 +00:00
|
|
|
|
|
|
|
/// Start a login process, from a request sent by the client.
|
|
|
|
///
|
|
|
|
/// The result must be kept for the next step.
|
|
|
|
pub fn start_login<R: RngCore + CryptoRng>(
|
|
|
|
rng: &mut R,
|
2021-06-23 18:33:36 +00:00
|
|
|
server_setup: &ServerSetup,
|
|
|
|
password_file: Option<ServerRegistration>,
|
2021-06-15 08:12:41 +00:00
|
|
|
credential_request: CredentialRequest,
|
2021-06-23 18:33:36 +00:00
|
|
|
username: &str,
|
2021-06-15 08:12:41 +00:00
|
|
|
) -> AuthenticationResult<ServerLoginStartResult> {
|
2021-06-08 20:23:46 +00:00
|
|
|
Ok(ServerLogin::start(
|
|
|
|
rng,
|
2021-06-23 18:33:36 +00:00
|
|
|
server_setup,
|
2021-06-08 20:23:46 +00:00
|
|
|
password_file,
|
|
|
|
credential_request,
|
2021-06-23 18:33:36 +00:00
|
|
|
username.as_bytes(),
|
2021-06-08 20:23:46 +00:00
|
|
|
ServerLoginStartParameters::default(),
|
|
|
|
)?)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Finish to authorize a new user, and get the session key to decrypt associated data.
|
2021-06-15 08:12:41 +00:00
|
|
|
pub fn finish_login(
|
|
|
|
login_start: ServerLogin,
|
|
|
|
credential_finalization: CredentialFinalization,
|
2021-06-08 20:23:46 +00:00
|
|
|
) -> AuthenticationResult<ServerLoginFinishResult> {
|
|
|
|
Ok(login_start.finish(credential_finalization)?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|