diff --git a/Cargo.lock b/Cargo.lock index ee16359..31de429 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,6 +261,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getset" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "group" version = "0.13.0" @@ -310,6 +322,7 @@ checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" name = "nkode-protocol" version = "0.1.0" dependencies = [ + "getset", "opaque-ke", "rand", "sha2", @@ -377,6 +390,28 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.103" diff --git a/Cargo.toml b/Cargo.toml index 102587c..10eb996 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,5 @@ opaque-ke = { version = "4.0.1",default-features = true, features = [ "std","arg rand = { version = "0.8.5", features = ["std"] } sha2 = "0.10.9" uuid = "1.19.0" +getset = "0.1.6" diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..58163f5 --- /dev/null +++ b/src/client.rs @@ -0,0 +1,92 @@ +use opaque_ke::argon2::password_hash::rand_core::OsRng; +use opaque_ke::{ + CredentialFinalization, CredentialRequest, RegistrationRequest, + ClientLogin, ClientLoginFinishParameters, ClientRegistration, + ClientRegistrationFinishParameters +}; +use uuid::Uuid; +use crate::protocol::{PasswordFile, KeyLoginPhaseISession, KeyRegisterSession, NKodeCipherSuite}; + +trait ServerConnectionRegister { + async fn start( + &mut self, + identifier: &[u8], + message: &RegistrationRequest + ) -> Result; + + async fn finish( + &mut self, + session_id: &Uuid, + password_file: PasswordFile, + ) -> Result<(), String>; +} + +trait ServerConnectionLogin { + async fn start( + &mut self, + identifier: &[u8], + request_bytes: &CredentialRequest + ) -> Result; + + async fn finish( + &mut self, + session_id: &Uuid, + message: &CredentialFinalization + ) -> Result<(), String>; +} + +struct AuthenticationData { + identifier: Vec, + secret: Vec, +} + +impl AuthenticationData { + fn from_secret_key(email: &String, secret_key: &[u8]) -> Self { + Self { + identifier: email.as_bytes().to_vec(), + secret: secret_key.to_vec(), + } + } + + fn from_code(email: &String, code: &[usize]) -> Self { + let mut secret = Vec::with_capacity(code.len() * 8); + for &n in code { + // fixed-width so it's stable across 32-bit vs 64-bit platforms + secret.extend_from_slice(&(n as u64).to_le_bytes()); + } + Self { + identifier: email.as_bytes().to_vec(), + secret, + } + } +} + +struct OpaqueAuthentication; + +impl OpaqueAuthentication { + async fn register( + key_data: &AuthenticationData, + server: &mut impl ServerConnectionRegister + ) -> Result<(), String> + { + let mut client_rng = OsRng; + let client_reg_start = ClientRegistration::::start(&mut client_rng, &key_data.secret).expect("error starting registration"); + let server_response = server.start(&key_data.identifier, &client_reg_start.message).await.expect("error getting server response"); + let client_finish = client_reg_start.state.finish(&mut client_rng, &key_data.secret, server_response.response().clone(), ClientRegistrationFinishParameters::default()).expect(""); + server.finish(server_response.session_id(), client_finish.message.serialize()).await.expect("server to finish secret reg without error"); + Ok(()) + } + + async fn login( + auth_data: &AuthenticationData, + server: &mut impl ServerConnectionLogin + ) -> Result, String> + { + let mut client_rng = OsRng; + let client_start = ClientLogin::::start(&mut client_rng, &auth_data.secret).expect("client secret key login to start result"); + let server_response = server.start(&auth_data.identifier, &client_start.message).await.expect("server secret key login start response"); + let client_finish = client_start.state.finish(&mut client_rng, &auth_data.secret, server_response.response().clone(), ClientLoginFinishParameters::default()).expect(""); + server.finish(server_response.session_id(), &client_finish.message).await.expect("server secret key login to finish"); + Ok(client_finish.session_key.to_vec()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7d79ae5..617ad7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,3 @@ mod protocol; +mod client; +mod server; diff --git a/src/protocol.rs b/src/protocol.rs index 2f854fb..143d371 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -8,10 +8,11 @@ use opaque_ke::generic_array::GenericArray; use uuid::Uuid; use opaque_ke::rand::rngs::OsRng; use std::marker::PhantomData; +use getset::Getters; pub const NONCE_SIZE: usize = 12; -pub const SECRET_KEY_SIZE: usize = 16; pub const SESSION_KEY_SIZE: usize = 32; +pub const SECRET_KEY_SIZE: usize = 16; pub struct NKodeCipherSuite; @@ -23,12 +24,16 @@ impl CipherSuite for NKodeCipherSuite { pub type NKodeServerSetup = ServerSetup, OprfSeed>; + +#[derive(Debug, Clone, PartialEq, Eq, Getters)] pub struct RegisterSession { + #[get = "pub"] response: RegistrationResponse, + #[get = "pub"] session_id: Uuid } -type PasswordFile = GenericArray>; +pub type PasswordFile = GenericArray>; pub async fn register_secret_key( @@ -48,8 +53,11 @@ where Ok(()) } +#[derive(Debug, Clone, PartialEq, Eq, Getters)] pub struct LoginSession { + #[get = "pub"] response: CredentialResponse, + #[get = "pub"] session_id: Uuid } @@ -66,6 +74,7 @@ where server.finish(&server_response.session_id, client_finish.message).await.expect("server secret key login to finish"); Ok(client_finish.session_key.to_vec()) } + pub trait Repo {} pub trait Sessions {} diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..d9d5247 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,117 @@ +use std::marker::PhantomData; +use opaque_ke::{CredentialFinalization, CredentialRequest, Identifiers, RegistrationRequest}; +use crate::protocol::{KeyLoginPhaseISession, NKodeCipherSuite, PasswordFile}; +use uuid::Uuid; + +#[derive(Debug)] +enum AuthRepoError { + UserExists, + KeyNotRegistered, + CodeNotRegistered +} + + +trait AuthRepo { + fn new_key(email: String, password_file: PasswordFile) -> Result<(), AuthRepoError>; + fn new_code(email: String, password_file: PasswordFile) -> Result<(), AuthRepoError>; + fn has_code(email: String) -> bool; + fn has_key(email: String) -> bool; + fn get_key_passcode_file(email: String) -> Result; + fn get_code_passcode_file(email: String) -> Result; +} + +struct RegSession; +struct LoginSession; + +trait AuthSession { + fn new_reg_session(identifier: &[u8], request: &RegistrationRequest) -> Result; + fn get_reg_session(session_id: Uuid) -> Result; + fn new_login_session(identifier: &[u8], request: &CredentialRequest) -> Result; + fn get_login_session(session_id: Uuid) -> Result; +} + +struct OpaqueAuth { + user_repo: R, + session: S, + _state: PhantomData +} + +struct KeyAuthRegistration; +impl OpaqueAuth +{ + async fn start( + &mut self, + identifier: &[u8], + message: &RegistrationRequest + ) -> Result { + todo!() + } + + async fn finish( + &mut self, + session_id: &Uuid, + password_file: PasswordFile, + ) -> Result<(), String> { + todo!() + } +} + +struct KeyAuthLogin; +impl OpaqueAuth +{ + async fn start( + &mut self, + identifier: &[u8], + request_bytes: &CredentialRequest + ) -> Result { + todo!() + } + + async fn finish( + &mut self, + session_id: &Uuid, + message: &CredentialFinalization + ) -> Result<(), String> { + todo!() + } +} + +struct CodeAuthRegistration; +impl OpaqueAuth +{ + async fn start( + &mut self, + identifier: &[u8], + message: &RegistrationRequest + ) -> Result { + todo!() + } + + async fn finish( + &mut self, + session_id: &Uuid, + password_file: PasswordFile, + ) -> Result<(), String> { + todo!() + } +} + +struct CodeAuthLogin; +impl OpaqueAuth +{ + async fn start( + &mut self, + identifier: &[u8], + request_bytes: &CredentialRequest + ) -> Result { + todo!() + } + + async fn finish( + &mut self, + session_id: &Uuid, + message: &CredentialFinalization + ) -> Result<(), String> { + todo!() + } +}