easy-srp 0.3.0

easy-srp wraps the rust srp crate and provides an easy to use API.
Documentation
//! Server-side SRP implementation
//! 
//! Contains the `ServerAuthenticationWorkflow` for implementing the server
//! side of the SRP authentication.

use digest::Digest;
use serde::Serialize;
use srp::server::{SrpServer, SrpServerVerifier};
use getrandom::getrandom;

use crate::types::Result;

/// Server-side of the authentication workflow
/// 
/// This struct should be used on the server side to authenticate a
/// compatible SRP6a client.
/// Digest `D` specifies the digest algorithm used and therefore also implicitly
/// defines the key size of the common secret key.
pub struct ServerAuthenticationWorkflow<'s, D: Digest> {
  delegate: SrpServer<'s, D>,
}

impl<'s, D: Digest> ServerAuthenticationWorkflow<'s, D> {
  pub fn new(group: &'s crate::groups::SrpGroup) -> Self {
    return Self {
      delegate: SrpServer::<'s, D>::new(group),
    };
  }

  /// step2: server creates ephemeral key from random bytes and stored verifier
  /// 
  /// The private key `server_private_b` must not be exposed, but needs to
  /// be stored for future steps.
  /// The public key `server_public_b` and the `salt` must be sent to the
  /// client.
  /// 
  /// receive: `client_public_a` from client
  /// keep: `server_private_a`, `client_public_b`
  /// send: `server_public_a`, `salt` to client
  pub fn step2(&self, params: ServerStep2Params) -> Result<ServerStep2Result> {
    let mut server_private_b = vec![0 as u8; 128];
    getrandom(server_private_b.as_mut_slice())?;

    let server_public_b = self.delegate.compute_public_ephemeral(
      server_private_b.as_slice(), 
      params.stored_verifier);
    
    return Ok(ServerStep2Result {
      server_private_b,
      server_public_b
    });
  }

  /// step4: server-side: generate verifier
  /// 
  /// the `proof()` of the result should be sent to the client
  pub fn step4(&self, params: ServerStep4Params) -> Result<ServerStep4Result<D>> {
    let verifier = self.delegate.process_reply(
      params.server_private_b,
      params.stored_verifier, 
      params.client_public_a)?;

    verifier.verify_client(params.client_proof)?;
    
    return Ok(ServerStep4Result {
      verifier
    });
  }

  // step 6: client verifies proof

}

/// Parameters for step 2
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct ServerStep2Params<'p> {
  /// The verifier stored for the given user
  /// 
  /// Contains the verifier that has been stored for the given user during
  /// user registration.
  #[serde(with = "crate::util::base64_u8")]
  pub stored_verifier: &'p [u8],
}

// Result of step 2
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct ServerStep2Result {
  /// The server's private ephemeral key
  /// 
  /// This must be kept secret.
  #[serde(with = "crate::util::base64_vec_u8")]
  pub server_private_b: Vec<u8>,

  /// The server's public ephemeral key
  /// 
  /// This must be sent to the client.
  #[serde(with = "crate::util::base64_vec_u8")]
  pub server_public_b: Vec<u8>,
}

/// Parameters for step 4
/// 
/// Step 4 verifies the client proof.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct ServerStep4Params<'p> {
  /// The server's private ephemeral key generated in step 2
  #[serde(with = "crate::util::base64_u8")]
  pub server_private_b: &'p [u8],

  /// The verifier stored for the user during user registration
  #[serde(with = "crate::util::base64_u8")]
  pub stored_verifier: &'p [u8],

  /// The client's public key received as part of step 2
  #[serde(with = "crate::util::base64_u8")]
  pub client_public_a: &'p [u8],

  /// The client's proof
  /// 
  /// Verifying the client proof is a prerequesite for sending any encrypted
  /// data (including the server proof) to the client. Not verifying the
  /// client proof may enable brute force attacks on the user credentials.
  #[serde(with = "crate::util::base64_u8")]
  pub client_proof: &'p [u8],
}

/// Result of step 4
/// 
/// The result of step 4 can be used to verify the client's proof and
/// to generate a client proof, as well as to generate the common key.
pub struct ServerStep4Result<D: Digest> {
  verifier: SrpServerVerifier<D>,
}

impl<D: Digest> ServerStep4Result<D> {
  /// Get the common secret key
  /// 
  /// SRP6a authentication results in a secret key shared by the client
  /// and server.
  pub fn key(&self) -> &[u8] {
    return self.verifier.key();
  }

  /// Generate a server proof
  /// 
  /// The generated value can be used to proof to the client that the server
  /// is using the same secret key.
  pub fn proof(&self) -> &[u8] {
    return self.verifier.proof();
  }

  /// Verify the client's proof
  /// 
  /// This method verifies the the client's `proof` is correct, thereby 
  /// verifying that the client uses the same secret key as the server.
  pub fn verify_client(&self, reply: &[u8]) -> Result<()> {
    return self.verifier.verify_client(reply)
      .or_else(|err| Err(err.into()));
  }
}