lldap/model/src/opaque.rs

235 lines
9.1 KiB
Rust
Raw Normal View History

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>;
/// Wrapper around an opaque KeyPair to have type-checked public and private keys.
#[derive(Debug, Clone)]
pub struct KeyPair(pub opaque_ke::keypair::KeyPair<<DefaultSuite as CipherSuite>::Group>);
pub struct PublicKey<'a>(&'a opaque_ke::keypair::Key);
pub struct PrivateKey<'a>(&'a opaque_ke::keypair::Key);
impl <'a> std::ops::Deref for PublicKey<'a> {
type Target = &'a opaque_ke::keypair::Key;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl <'a> std::ops::Deref for PrivateKey<'a> {
type Target = &'a opaque_ke::keypair::Key;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl KeyPair {
pub fn private(&self) -> PrivateKey<'_> {
PrivateKey(self.0.private())
}
pub fn public(&self) -> PublicKey<'_> {
PublicKey(self.0.public())
}
pub fn from_private_key_slice(input: &[u8]) -> std::result::Result<Self, opaque_ke::errors::InternalPakeError> {
opaque_ke::keypair::KeyPair::<<DefaultSuite as CipherSuite>::Group>::from_private_key_slice(input).map(Self)
}
}
2021-06-08 21:24:33 +00:00
/// A wrapper around argon2 to provide the [`opaque_ke::slow_hash::SlowHash`] trait.
pub struct ArgonHasher;
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,
time_cost: 5,
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 {
pub use super::*;
2021-06-08 20:23:46 +00:00
/// Methods to register a new user, from the client side.
pub mod registration {
pub use super::*;
2021-06-15 08:12:41 +00:00
pub type ClientRegistration = opaque_ke::ClientRegistration<DefaultSuite>;
pub type ClientRegistrationStartResult = opaque_ke::ClientRegistrationStartResult<DefaultSuite>;
pub type ClientRegistrationFinishResult = opaque_ke::ClientRegistrationFinishResult<DefaultSuite>;
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> {
Ok(ClientRegistration::start(
2021-06-08 20:23:46 +00:00
rng,
password.as_bytes(),
)?)
}
/// 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 {
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>;
pub use opaque_ke::{
2021-06-15 08:12:41 +00:00
ClientLoginFinishParameters,
ClientLoginStartParameters,
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> {
Ok(ClientLogin::start(
2021-06-08 20:23:46 +00:00
rng,
password.as_bytes(),
ClientLoginStartParameters::default(),
)?)
}
/// 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 {
pub use super::*;
2021-06-15 08:12:41 +00:00
pub type ServerRegistration = opaque_ke::ServerRegistration<DefaultSuite>;
2021-06-08 20:23:46 +00:00
/// Methods to register a new user, from the server side.
pub mod registration {
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>;
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.
pub fn start_registration<R: RngCore + CryptoRng>(
rng: &mut R,
2021-06-15 08:12:41 +00:00
registration_request: RegistrationRequest,
server_public_key: PublicKey<'_>,
2021-06-15 08:12:41 +00:00
) -> AuthenticationResult<ServerRegistrationStartResult> {
Ok(ServerRegistration::start(
2021-06-08 20:23:46 +00:00
rng,
registration_request,
*server_public_key,
2021-06-08 20:23:46 +00:00
)?)
}
/// Finish to register a new user, and get the data to store in the database.
pub fn get_password_file(
2021-06-15 08:12:41 +00:00
registration_start: ServerRegistration,
registration_upload: RegistrationUpload,
) -> AuthenticationResult<ServerRegistration> {
2021-06-08 20:23:46 +00:00
Ok(registration_start.finish(registration_upload)?)
}
}
/// Methods to handle user login, from the server-side.
pub mod login {
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-15 08:12:41 +00:00
password_file: ServerRegistration,
server_private_key: PrivateKey<'_>,
2021-06-15 08:12:41 +00:00
credential_request: CredentialRequest,
) -> AuthenticationResult<ServerLoginStartResult> {
2021-06-08 20:23:46 +00:00
Ok(ServerLogin::start(
rng,
password_file,
*server_private_key,
2021-06-08 20:23:46 +00:00
credential_request,
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)?)
}
}
}