stopping for the night

This commit is contained in:
2025-12-16 18:50:09 -06:00
parent be95241ed4
commit 16c8f2d6aa
8 changed files with 158 additions and 253 deletions

View File

@@ -1,27 +1,29 @@
use std::marker::PhantomData;
use nkode_rs::nkode_core::keypad::Keypad;
use crate::models::app::{CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, ClientAuthAPI, ICON_ID_SIZE};
use crate::models::app::{OpaqueAPI, AuthAPI, CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, ICON_ID_SIZE, LoginSession};
use crate::models::email::Email;
use crate::models::opaque::UserSecretKey;
use crate::models::opaque::{OpaqueLoginSession, UserSecretKey};
use anyhow::Result;
use nkode_rs::nkode_core::nkode_cipher::NKodeCipher;
use nkode_rs::from_bytes::FromBytes;
use nkode_rs::nkode_core::chacha20prng::Nonce;
use async_trait::async_trait;
use nkode_rs::nkode_core::policy::{NKodePolicy, DEFAULT_POLICY};
use crate::opaque::client::{AuthenticationData, OpaqueAuthLogin, OpaqueAuthRegister, ServerConnectionLogin, ServerConnectionRegister};
pub struct Login;
pub struct Register;
pub struct ClientAppKey<State, S: ClientAuthAPI> {
pub struct ClientAppKey<State, S: OpaqueAPI> {
api: S,
email: Email,
user_secret_key: UserSecretKey,
_state: PhantomData<State>
}
impl <S: ClientAuthAPI> ClientAppKey<Register,S> {
impl <S: OpaqueAPI> ClientAppKey<Register,S> {
pub async fn register(self) -> Result<ClientAppKey<Login, S>, String> {
// self.repo.set_secret_key(&self.email, &self.user_secret_key).await?;
self.api.register_key(&self.email, &self.user_secret_key).await?;
Ok(ClientAppKey {
api: self.api,
@@ -32,7 +34,7 @@ impl <S: ClientAuthAPI> ClientAppKey<Register,S> {
}
}
impl <S: ClientAuthAPI> ClientAppKey<Login,S> {
impl <S: OpaqueAPI> ClientAppKey<Login,S> {
pub async fn login(self) -> Result<ClientAppKeyLoggedIn<S>,String> {
let key_login = self.api.login_key(&self.email, &self.user_secret_key).await?;
Ok(ClientAppKeyLoggedIn{
@@ -44,14 +46,14 @@ impl <S: ClientAuthAPI> ClientAppKey<Login,S> {
}
}
pub struct ClientAppKeyLoggedIn<S: ClientAuthAPI> {
pub struct ClientAppKeyLoggedIn<S: OpaqueAPI> {
api: S,
email: Email,
user_secret_key: UserSecretKey,
key_login: KeyLoginSession,
}
impl <S: ClientAuthAPI> ClientAppKeyLoggedIn<S> {
impl <S: OpaqueAPI + AuthAPI> ClientAppKeyLoggedIn<S> {
pub async fn register_code(self) -> Result<ClientAppCodeRegister<S>, String> {
let icon_nonce = Nonce::new();
let icons = self.get_icons(&icon_nonce).await?;
@@ -98,7 +100,7 @@ impl <S: ClientAuthAPI> ClientAppKeyLoggedIn<S> {
}
}
pub struct ClientAppCodeRegister<S: ClientAuthAPI> {
pub struct ClientAppCodeRegister<S: OpaqueAPI> {
api: S,
email: Email,
user_secret_key: UserSecretKey,
@@ -108,7 +110,7 @@ pub struct ClientAppCodeRegister<S: ClientAuthAPI> {
keypad: Keypad,
}
impl <S: ClientAuthAPI>ClientAppCodeRegister<S> {
impl <S: OpaqueAPI + AuthAPI>ClientAppCodeRegister<S> {
pub async fn register(self, selected_icons: Vec<IconID>) -> Result<ClientAppCodeLogin<S>, String> {
let policy = self.api.get_policy().await?;
let keypad = Keypad::new(policy.clone());
@@ -137,7 +139,7 @@ impl <S: ClientAuthAPI>ClientAppCodeRegister<S> {
}
}
pub struct ClientAppCodeLogin<S: ClientAuthAPI> {
pub struct ClientAppCodeLogin<S: OpaqueAPI> {
api: S,
email: Email,
mask: Vec<u64>,
@@ -146,7 +148,7 @@ pub struct ClientAppCodeLogin<S: ClientAuthAPI> {
cipher: NKodeCipher
}
impl <S: ClientAuthAPI>ClientAppCodeLogin<S> {
impl <S: OpaqueAPI>ClientAppCodeLogin<S> {
pub fn sort_icons(&self) -> Vec<Icon> {
nkode_rs::tensor::reorder(
&self.icons,
@@ -158,4 +160,90 @@ impl <S: ClientAuthAPI>ClientAppCodeLogin<S> {
let passcode = self.cipher.decipher(selected_keys, self.keypad.indices(), &self.mask).map_err(|e| format!("invalid keys: {e}"))?;
self.api.login_code(&self.email, &passcode).await
}
}
}
pub struct ClientAuth<
R: ServerConnectionRegister + Clone,
L: ServerConnectionLogin + Clone,
K: AuthAPI
> {
opaque_key_register: OpaqueAuthRegister<R>,
opaque_key_login: OpaqueAuthLogin<L>,
opaque_code_register: OpaqueAuthRegister<R>,
opaque_code_login: OpaqueAuthLogin<L>,
nkode_api: K,
}
#[async_trait]
impl<R, L, K> OpaqueAPI for ClientAuth<R, L,K>
where
R: ServerConnectionRegister + Clone + Sync + Send,
L: ServerConnectionLogin + Clone + Sync + Send,
K: AuthAPI + Sync + Send,
{
async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String> {
let auth_data = AuthenticationData::from_secret_key(email.as_str(), secret_key.as_slice());
self.opaque_key_register.register(&auth_data).await.map_err(|e| format!("error: {}", e))
}
async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoginSession, data: &CodeLoginData) -> Result<(), String> {
let auth_data = AuthenticationData::from_code(email.as_str(), passcode);
self.opaque_code_register.register(&auth_data).await.map_err(|e| format!("error: {}", e))
}
async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoginSession, String> {
let auth_data = AuthenticationData::from_secret_key(&email.as_str(), secret_key.as_slice());
let session_key = self.opaque_key_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?;
Ok(KeyLoginSession(
LoginSession {
email: email.clone(),
session_key
}
))
}
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String> {
let auth_data = AuthenticationData::from_code(email.as_str(), passcode);
let session_key = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?;
Ok(CodeLoginSession(
LoginSession {
email: email.clone(),
session_key
}
))
}
}
#[async_trait]
impl<R, L, K> AuthAPI for ClientAuth<R, L, K>
where
R: ServerConnectionRegister + Clone + Sync + Send,
L: ServerConnectionLogin + Clone + Sync + Send,
K: AuthAPI + Sync + Send,
{
async fn get_new_icons(
&self,
key_login_session: &KeyLoginSession,
) -> Result<Vec<Icon>, String> {
self.nkode_api
.get_new_icons(key_login_session)
.await
}
async fn get_login_data(
&self,
key_login_session: &KeyLoginSession,
) -> Result<CodeLoginData, String> {
self.nkode_api
.get_login_data(key_login_session)
.await
}
async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String> {
self.nkode_api.is_code_registered(key_login_session).await
}
async fn get_policy(&self) -> Result<NKodePolicy, String> {
Ok(DEFAULT_POLICY)
}
}

View File

@@ -1,197 +0,0 @@
// // in_memory_server.rs
// use std::collections::HashMap;
// use std::hash::Hash;
// use std::sync::Arc;
// use nkode_rs::nkode_core::policy::NKodePolicy;
// use tokio::sync::RwLock;
//
// use crate::models::app::{
// CodeLoginData, CodeLoginSession, Icon, KeyLoginSession, ClientAuthAPI,
// };
// use crate::models::email::Email;
// use crate::models::opaque::UserSecretKey;
//
//
// #[derive(Clone)]
// pub struct InMemoryServer<FKeySess, FCodeSess> {
// state: Arc<RwLock<State>>,
// policy: NKodePolicy,
// icon_pool: Vec<Icon>,
// new_key_session: FKeySess,
// new_code_session: FCodeSess,
// }
//
// struct State {
// users: HashMap<Email, UserRecord>,
// key_sessions: HashMap<KeyLoginSession, Email>,
// code_sessions: HashMap<CodeLoginSession, Email>,
// }
//
// struct UserRecord {
// secret_key: UserSecretKey,
// code: Option<StoredCode>,
// }
//
// struct StoredCode {
// passcode: Vec<u64>,
// data: CodeLoginData,
// }
//
// impl Default for State {
// fn default() -> Self {
// Self {
// users: HashMap::new(),
// key_sessions: HashMap::new(),
// code_sessions: HashMap::new(),
// }
// }
// }
//
// impl<FKeySess, FCodeSess> InMemoryServer<FKeySess, FCodeSess> {
// /// `icon_pool` is what `get_new_icons()` returns (cloned) each time.
// /// `new_key_session` and `new_code_session` let you decide how sessions are created
// /// without changing the ServerAPI trait or guessing constructors.
// pub fn new(
// policy: NKodePolicy,
// icon_pool: Vec<Icon>,
// new_key_session: FKeySess,
// new_code_session: FCodeSess,
// ) -> Self {
// Self {
// state: Arc::new(RwLock::new(State::default())),
// policy,
// icon_pool,
// new_key_session,
// new_code_session,
// }
// }
// }
//
// impl<FKeySess, FCodeSess> InMemoryServer<FKeySess, FCodeSess>
// where
// // bounds needed for HashMap keys/values and cloning across calls
// Email: Eq + Hash + Clone,
// UserSecretKey: Clone + PartialEq,
// Icon: Clone,
// CodeLoginData: Clone,
// KeyLoginSession: Eq + Hash + Clone,
// CodeLoginSession: Eq + Hash + Clone,
// FKeySess: Fn() -> KeyLoginSession + Send + Sync + 'static,
// FCodeSess: Fn() -> CodeLoginSession + Send + Sync + 'static,
// {
// fn err(msg: impl Into<String>) -> Result<(), String> {
// Err(msg.into())
// }
//
// fn ok<T>(v: T) -> Result<T, String> {
// Ok(v)
// }
//
// async fn email_from_key_session(&self, sess: &KeyLoginSession) -> Result<Email, String> {
// let st = self.state.read().await;
// st.key_sessions
// .get(sess)
// .cloned()
// .ok_or_else(|| "invalid key login session".to_string())
// }
// }
//
// impl<FKeySess, FCodeSess> ClientAuthAPI for InMemoryServer<FKeySess, FCodeSess>
// where
// Email: Eq + Hash + Clone,
// UserSecretKey: Clone + PartialEq,
// Icon: Clone,
// CodeLoginData: Clone,
// KeyLoginSession: Eq + Hash + Clone,
// CodeLoginSession: Eq + Hash + Clone,
//
// FKeySess: Fn() -> KeyLoginSession + Send + Sync + 'static,
// FCodeSess: Fn() -> CodeLoginSession + Send + Sync + 'static,
// {
// async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String> {
// let mut st = self.state.write().await;
//
// if st.users.contains_key(email) {
// return Err("email already registered".to_string());
// }
//
// st.users.insert(
// email.clone(),
// UserRecord {
// secret_key: secret_key.clone(),
// code: None,
// },
// );
//
// Ok(())
// }
//
// async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoginSession, String> {
// let mut st = self.state.write().await;
//
// let user = st.users.get(email).ok_or_else(|| "unknown email".to_string())?;
// if &user.secret_key != secret_key {
// return Err("invalid secret key".to_string());
// }
// let sess = (self.new_key_session)();
// st.key_sessions.insert(sess.clone(), email.clone());
// Ok(sess)
// }
//
// async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String> {
// let email = self.email_from_key_session(key_login_session).await?;
// let st = self.state.read().await;
// let user = st.users.get(&email).ok_or_else(|| "unknown email".to_string())?;
// Ok(user.code.is_some())
// }
//
// async fn get_policy(&self) -> Result<NKodePolicy, String> {
// Ok(self.policy.clone())
// }
//
// async fn get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result<Vec<Icon>, String> {
// // Validate session (mimics auth gate)
// let _email = self.email_from_key_session(key_login_session).await?;
// Ok(self.icon_pool.clone())
// }
//
// async fn register_code(
// &self,
// email: &Email,
// passcode: &[u64],
// key_login_session: &KeyLoginSession,
// data: &CodeLoginData,
// ) -> Result<(), String> {
// let sess_email = self.email_from_key_session(key_login_session).await?;
// if &sess_email != email {
// return Err("session email mismatch".to_string());
// }
// let mut st = self.state.write().await;
// let user = st.users.get_mut(email).ok_or_else(|| "unknown email".to_string())?;
// user.code = Some(StoredCode {
// passcode: passcode.to_vec(),
// data: data.clone(),
// });
// Ok(())
// }
//
// async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result<CodeLoginData, String> {
// let email = self.email_from_key_session(key_login_session).await?;
// let st = self.state.read().await;
// let user = st.users.get(&email).ok_or_else(|| "unknown email".to_string())?;
// let code = user.code.as_ref().ok_or_else(|| "code not registered".to_string())?;
// Ok(code.data.clone())
// }
//
// async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String> {
// let mut st = self.state.write().await;
// let user = st.users.get(email).ok_or_else(|| "unknown email".to_string())?;
// let code = user.code.as_ref().ok_or_else(|| "code not registered".to_string())?;
// if code.passcode.as_slice() != passcode {
// return Err("invalid passcode".to_string());
// }
// let sess = (self.new_code_session)();
// st.code_sessions.insert(sess.clone(), email.clone());
// Ok(sess)
// }
// }

View File

@@ -1,20 +1,18 @@
use async_trait::async_trait;
use nkode_rs::nkode_core::chacha20prng::Nonce; use nkode_rs::nkode_core::keypad::Keypad;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use getset::Getters;
use nkode_rs::from_bytes::FromBytes;
use nkode_rs::nkode_core::policy::NKodePolicy;
use crate::models::email::Email;
use crate::models::opaque::{OpaqueSessionKey, UserSecretKey};
struct LoginSession {
email: Email,
session_id: Uuid,
session_key: OpaqueSessionKey,
pub struct LoginSession {
pub(crate) email: Email,
pub(crate) session_key: OpaqueSessionKey,
}
pub struct KeyLoginSession(LoginSession);
pub struct CodeLoginSession(LoginSession);
pub struct KeyLoginSession(pub(crate) LoginSession);
pub struct CodeLoginSession(pub(crate) LoginSession);
pub const ICON_ID_SIZE: usize = 32;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -44,8 +42,6 @@ impl Icon {
pub struct CodeLoginData {
#[get = "pub"]
pub(crate) mask: Vec<u64>,
// #[get = "pub"]
// pub(crate) icons: Vec<Icon>,
#[get = "pub"]
pub(crate) cipher_nonce: Nonce,
#[get = "pub"]
@@ -54,11 +50,16 @@ pub struct CodeLoginData {
pub(crate) keypad: Keypad,
}
pub trait ClientAuthAPI {
#[async_trait]
pub trait OpaqueAPI {
async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String>;
async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoginSession, data: &CodeLoginData) -> Result<(), String>;
async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoginSession, String>;
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String>;
}
#[async_trait]
pub trait AuthAPI {
async fn get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result<Vec<Icon>, String>;
async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result<CodeLoginData, String>;
async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String>;

View File

@@ -11,8 +11,7 @@ use nkode_rs::from_bytes::FromBytes;
const USER_KEY_SIZE: usize = 16;
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Clone, Eq, PartialEq)]
pub struct UserSecretKey(Zeroizing<[u8; USER_KEY_SIZE]>);
impl UserSecretKey {
@@ -20,6 +19,10 @@ impl UserSecretKey {
let out = blake3::derive_key("your-app chacha20 secret key v1", &self.0.as_slice());
SecretKey::from_bytes(&out).unwrap()
}
pub fn as_slice(&self) -> &[u8] {
self.0.as_slice()
}
}
impl FromBytes<USER_KEY_SIZE> for UserSecretKey {
@@ -30,6 +33,7 @@ impl FromBytes<USER_KEY_SIZE> for UserSecretKey {
const OPAQUE_SESSION_KEY_SIZE: usize = 64;
#[derive(Debug)]
pub struct OpaqueSessionKey(Zeroizing<[u8; OPAQUE_SESSION_KEY_SIZE]>);
impl FromBytes<OPAQUE_SESSION_KEY_SIZE> for OpaqueSessionKey {
@@ -52,13 +56,13 @@ pub type NKodeServerSetup = ServerSetup<NKodeCipherSuite, PrivateKey<Ristretto25
pub type PasswordFile = GenericArray<u8, RegistrationUploadLen<NKodeCipherSuite>>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LoginSession {
pub struct OpaqueLoginSession {
pub response: CredentialResponse<NKodeCipherSuite>,
pub session_id: Uuid
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RegisterSession {
pub struct OpaqueRegisterSession {
pub response: RegistrationResponse<NKodeCipherSuite>,
pub session_id: Uuid
}

View File

@@ -1,6 +1,7 @@
use std::fmt;
use async_trait::async_trait;
use nkode_rs::from_bytes::FromBytes;
use uuid::Uuid;
use opaque_ke::rand::rngs::OsRng;
use opaque_ke::{
ClientLogin, ClientLoginFinishParameters,
@@ -8,10 +9,8 @@ use opaque_ke::{
CredentialFinalization, CredentialRequest,
RegistrationRequest,
};
use crate::models::opaque::{RegisterSession, LoginSession, NKodeCipherSuite, PasswordFile, OpaqueSessionKey};
use crate::models::app::KeyLoginSession;
use crate::models::opaque::{OpaqueRegisterSession, OpaqueLoginSession, NKodeCipherSuite, PasswordFile, OpaqueSessionKey};
#[derive(Debug)]
pub enum ClientAuthError {
@@ -19,6 +18,17 @@ pub enum ClientAuthError {
Transport(String),
}
impl fmt::Display for ClientAuthError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ClientAuthError::Opaque(msg) => write!(f, "{}", msg),
ClientAuthError::Transport(msg) => write!(f, "transport error: {}", msg),
}
}
}
impl std::error::Error for ClientAuthError {}
pub struct AuthenticationData {
pub identifier: Vec<u8>,
pub secret: Vec<u8>,
@@ -32,11 +42,11 @@ impl AuthenticationData {
}
}
pub fn from_code(email: &str, code: &[usize]) -> Self {
pub fn from_code(email: &str, code: &[u64]) -> Self {
// fixed-width so it's stable across 32-bit vs 64-bit platforms
let mut secret = Vec::with_capacity(code.len() * 8);
for &n in code {
secret.extend_from_slice(&(n as u64).to_le_bytes());
secret.extend_from_slice(&(n).to_le_bytes());
}
Self {
identifier: email.as_bytes().to_vec(),
@@ -51,7 +61,7 @@ pub trait ServerConnectionRegister {
&self,
identifier: &[u8],
message: &RegistrationRequest<NKodeCipherSuite>,
) -> Result<RegisterSession, ClientAuthError>;
) -> Result<OpaqueRegisterSession, ClientAuthError>;
async fn finish(
&self,
@@ -66,7 +76,7 @@ pub trait ServerConnectionLogin {
&self,
identifier: &[u8],
request: &CredentialRequest<NKodeCipherSuite>,
) -> Result<LoginSession, ClientAuthError>;
) -> Result<OpaqueLoginSession, ClientAuthError>;
async fn finish(
&self,
@@ -99,7 +109,6 @@ impl <R: ServerConnectionRegister + Clone>OpaqueAuthRegister<R> {
pub async fn register(
&self,
auth: &AuthenticationData,
// server: &mut impl ServerConnectionRegister,
) -> Result<(), ClientAuthError> {
let mut rng = OsRng;
let start = ClientRegistration::<NKodeCipherSuite>::start(&mut rng, &auth.secret)
@@ -131,7 +140,7 @@ impl <L: ServerConnectionLogin + Clone>OpaqueAuthLogin<L> {
pub async fn login(
&self,
auth: &AuthenticationData,
) -> Result<Vec<u8>, ClientAuthError> {
) -> Result<OpaqueSessionKey, ClientAuthError> {
let mut rng = OsRng;
let start = ClientLogin::<NKodeCipherSuite>::start(&mut rng, &auth.secret)
.map_err(|e| ClientAuthError::Opaque(format!("client login start: {e:?}")))?;
@@ -153,6 +162,9 @@ impl <L: ServerConnectionLogin + Clone>OpaqueAuthLogin<L> {
.finish(&server_start.session_id, &finish.message)
.await
.map_err(|e| ClientAuthError::Transport(format!("server login finish: {e:?}")))?;
Ok(finish.session_key.to_vec())
Ok(
OpaqueSessionKey::from_bytes(finish.session_key.as_slice())
.map_err(|e| ClientAuthError::Opaque(format!("from bytes error {e:?}")))?
)
}
}

View File

@@ -5,7 +5,7 @@ use opaque_ke::{
ServerRegistration,
};
use uuid::Uuid;
use crate::models::opaque::{LoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, RegisterSession};
use crate::models::opaque::{OpaqueLoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, OpaqueRegisterSession};
use crate::repository::opaque::repos::{OpaqueDatabaseRepo, AuthRepoError, OpaqueSessionRepo};
pub struct RegCache {
@@ -79,7 +79,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
&mut self,
identifier: &[u8],
request: RegistrationRequest<NKodeCipherSuite>,
) -> Result<RegisterSession, String> {
) -> Result<OpaqueRegisterSession, String> {
K::prereq_for_register(&self.user_repo, identifier)
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
let start = ServerRegistration::<NKodeCipherSuite>::start(
@@ -91,7 +91,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
.new_reg_session(identifier)
.map_err(|e| format!("reg cache: {e}"))?;
Ok(RegisterSession { session_id: cache.session_id, response: start.message })
Ok(OpaqueRegisterSession { session_id: cache.session_id, response: start.message })
}
pub async fn reg_finish<K: CredKind>(
@@ -115,14 +115,13 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
&mut self,
identifier: &[u8],
request: CredentialRequest<NKodeCipherSuite>,
) -> Result<LoginSession, String> {
) -> Result<OpaqueLoginSession, String> {
let password_file = K::get_pf(&self.user_repo, identifier)
.map_err(|e| format!("repo read: {e:?}"))?;
let password_file =
ServerRegistration::<NKodeCipherSuite>::deserialize(password_file.as_slice())
.map_err(|e| format!("pf deserialize: {e:?}"))?;
let mut server_rng = OsRng;
let start = ServerLogin::start(
&mut server_rng,
@@ -132,12 +131,10 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
identifier,
ServerLoginParameters::default(),
).map_err(|e| format!("opaque login start: {e:?}"))?;
let cache = self.session
.new_login_session(identifier, start.state)
.map_err(|e| format!("login cache: {e}"))?;
Ok(LoginSession { session_id: cache.session_id, response: start.message })
Ok(OpaqueLoginSession { session_id: cache.session_id, response: start.message })
}
pub async fn login_finish<K: CredKind>(

View File

@@ -4,7 +4,7 @@ use tokio::sync::Mutex;
use std::sync::Arc;
use uuid::Uuid;
use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest};
use crate::models::opaque::{LoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, RegisterSession};
use crate::models::opaque::{OpaqueLoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, OpaqueRegisterSession};
use crate::opaque::client::{ClientAuthError, ServerConnectionLogin, ServerConnectionRegister};
use crate::opaque::server::{OpaqueAuth, CredKind, Key, Code};
use crate::repository::opaque::in_memory::in_memory_auth_repo::InMemoryAuthRepo;
@@ -31,13 +31,13 @@ pub type InMemoryCodeServer = InMemoryServer<Code>;
#[async_trait]
impl<K> ServerConnectionRegister for InMemoryServer<K>
where
K: CredKind + Send + Sync,
K: CredKind + Sync,
{
async fn start(
&self,
identifier: &[u8],
message: &RegistrationRequest<NKodeCipherSuite>,
) -> Result<RegisterSession, ClientAuthError> {
) -> Result<OpaqueRegisterSession, ClientAuthError> {
// Server API takes ownership; client trait gives us a reference.
// opaque-ke request types are typically Clone; if not, you'll need to adjust signatures.
self.auth.lock().await
@@ -67,7 +67,7 @@ where
&self,
identifier: &[u8],
request: &CredentialRequest<NKodeCipherSuite>,
) -> Result<LoginSession, ClientAuthError> {
) -> Result<OpaqueLoginSession, ClientAuthError> {
self.auth.lock().await
.login_start::<K>(identifier, request.clone())
.await

View File

@@ -12,10 +12,10 @@ async fn opaque_key_registration_and_login_roundtrip() {
let auth_data = AuthenticationData::from_secret_key("a@b.com", b"supersecret16bytes");
auth_reg.register(&auth_data).await.expect("registration should succeed");
let login_reg = OpaqueAuthLogin::new(server);
let session_key =login_reg.login(&auth_data)
let _ =login_reg.login(&auth_data)
.await
.expect("login should succeed");
assert!(!session_key.is_empty());
// assert!(!session_key.is_empty());
}
#[tokio::test]
@@ -38,9 +38,9 @@ async fn opaque_login_fails_if_not_registered() {
async fn cannot_register_code_before_key() {
let mut rng = OsRng;
let server_setup = NKodeServerSetup::new(&mut rng);
let mut server = InMemoryCodeServer::new(server_setup);
let server = InMemoryCodeServer::new(server_setup);
let auth_reg = OpaqueAuthRegister::new(server.clone());
let auth = AuthenticationData::from_code("x@y.com", &[1usize,2,3,4]);
let auth = AuthenticationData::from_code("x@y.com", &[1u64,2,3,4]);
let err = auth_reg.register(&auth)
.await
.expect_err("should fail because key is not registered");