use base64::Engine;
use digest::Digest;
use srp::client::{SrpClient, SrpClientVerifier};
use getrandom::getrandom;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
use crate::types::Result;
pub struct ClientAuthenticationWorkflow<'c, D: Digest> {
delegate: SrpClient<'c, D>,
}
impl<'c, D: Digest> ClientAuthenticationWorkflow<'c, D> {
pub fn new(group: &'c crate::groups::SrpGroup) -> Self {
return Self {
delegate: SrpClient::<'c, D>::new(group),
};
}
pub fn step1(&self) -> Result<ClientStep1Result> {
let mut client_private_a = vec![0 as u8; 128];
getrandom(client_private_a.as_mut_slice())?;
let client_public_a = self.delegate.compute_public_ephemeral(client_private_a.as_slice());
return Ok(ClientStep1Result {
client_private_a,
client_public_a
});
}
pub fn step3(&self, params: ClientStep3Params) -> Result<ClientStep3Result<D>> {
let verifier = self.delegate.process_reply(
params.client_a,
params.username.as_bytes(),
params.password.as_bytes(),
params.salt,
params.server_public_b
)?;
return Ok(ClientStep3Result {
verifier
});
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ClientStep1Result {
#[serde(with = "crate::util::base64_vec_u8")]
pub client_private_a: Vec<u8>,
#[serde(with = "crate::util::base64_vec_u8")]
pub client_public_a: Vec<u8>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct ClientStep3Params<'p> {
#[serde(with = "crate::util::base64_u8")]
pub client_a: &'p [u8],
pub username: String,
pub password: String,
#[serde(with = "crate::util::base64_u8")]
pub salt: &'p [u8],
#[serde(with = "crate::util::base64_u8")]
pub server_public_b: &'p [u8],
}
pub struct ClientStep3Result<D: Digest> {
verifier: SrpClientVerifier<D>,
}
impl<D: Digest> ClientStep3Result<D> {
pub fn key(&self) -> &[u8] {
return self.verifier.key();
}
pub fn proof(&self) -> &[u8] {
return self.verifier.proof();
}
pub fn verify_server(&self, proof: &[u8]) -> Result<()> {
return self.verifier.verify_server(proof)
.or_else(|err| Err(err.into()));
}
}
pub struct ClientRegistrationWorkflow<'c, D: Digest> {
delegate: SrpClient<'c, D>,
}
impl<'c, D: Digest> ClientRegistrationWorkflow<'c, D> {
pub fn new(group: &'c crate::groups::SrpGroup) -> Self {
return Self {
delegate: SrpClient::<'c, D>::new(group),
};
}
pub fn generate_verifier(&self, params: GenerateVerifierParams) -> Result<Verifier> {
let GenerateVerifierParams {
username,
password,
salt
} = params;
let salt = if let Some(salt) = salt {
salt
} else {
let mut random_salt = vec![0 as u8; 32];
getrandom::getrandom(random_salt.as_mut_slice())?;
random_salt
};
let verifier = self.delegate.compute_verifier(
username.as_bytes(),
password.as_bytes(),
salt.as_slice());
return Ok(Verifier {
username,
salt,
verifier
});
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GenerateVerifierParams {
pub username: String,
pub password: String,
#[serde(with = "crate::util::base64_opt_vec_u8")]
pub salt: Option<Vec<u8>>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Verifier {
pub username: String,
#[serde(with = "crate::util::base64_vec_u8")]
pub salt: Vec<u8>,
#[serde(with = "crate::util::base64_vec_u8")]
pub verifier: Vec<u8>,
}
#[cfg(feature = "base64")]
impl Verifier {
pub fn salt_base64(&self) -> String {
let engine = base64::engine::general_purpose::STANDARD_NO_PAD;
let result = engine.encode(self.salt.as_slice());
return result;
}
pub fn verifier_base64(&self) -> String {
let engine = base64::engine::general_purpose::STANDARD_NO_PAD;
let result = engine.encode(self.verifier.as_slice());
return result;
}
}