outline opaque auth
This commit is contained in:
35
Cargo.lock
generated
35
Cargo.lock
generated
@@ -261,6 +261,18 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"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]]
|
[[package]]
|
||||||
name = "group"
|
name = "group"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
@@ -310,6 +322,7 @@ checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
|||||||
name = "nkode-protocol"
|
name = "nkode-protocol"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"getset",
|
||||||
"opaque-ke",
|
"opaque-ke",
|
||||||
"rand",
|
"rand",
|
||||||
"sha2",
|
"sha2",
|
||||||
@@ -377,6 +390,28 @@ dependencies = [
|
|||||||
"zerocopy",
|
"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]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.103"
|
version = "1.0.103"
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ opaque-ke = { version = "4.0.1",default-features = true, features = [ "std","arg
|
|||||||
rand = { version = "0.8.5", features = ["std"] }
|
rand = { version = "0.8.5", features = ["std"] }
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
uuid = "1.19.0"
|
uuid = "1.19.0"
|
||||||
|
getset = "0.1.6"
|
||||||
|
|
||||||
|
|||||||
92
src/client.rs
Normal file
92
src/client.rs
Normal file
@@ -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<NKodeCipherSuite>
|
||||||
|
) -> Result<KeyRegisterSession, String>;
|
||||||
|
|
||||||
|
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<NKodeCipherSuite>
|
||||||
|
) -> Result<KeyLoginPhaseISession, String>;
|
||||||
|
|
||||||
|
async fn finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
message: &CredentialFinalization<NKodeCipherSuite>
|
||||||
|
) -> Result<(), String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AuthenticationData {
|
||||||
|
identifier: Vec<u8>,
|
||||||
|
secret: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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::<NKodeCipherSuite>::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<Vec<u8>, String>
|
||||||
|
{
|
||||||
|
let mut client_rng = OsRng;
|
||||||
|
let client_start = ClientLogin::<NKodeCipherSuite>::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())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,3 @@
|
|||||||
mod protocol;
|
mod protocol;
|
||||||
|
mod client;
|
||||||
|
mod server;
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ use opaque_ke::generic_array::GenericArray;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use opaque_ke::rand::rngs::OsRng;
|
use opaque_ke::rand::rngs::OsRng;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use getset::Getters;
|
||||||
|
|
||||||
pub const NONCE_SIZE: usize = 12;
|
pub const NONCE_SIZE: usize = 12;
|
||||||
pub const SECRET_KEY_SIZE: usize = 16;
|
|
||||||
pub const SESSION_KEY_SIZE: usize = 32;
|
pub const SESSION_KEY_SIZE: usize = 32;
|
||||||
|
pub const SECRET_KEY_SIZE: usize = 16;
|
||||||
|
|
||||||
pub struct NKodeCipherSuite;
|
pub struct NKodeCipherSuite;
|
||||||
|
|
||||||
@@ -23,12 +24,16 @@ impl CipherSuite for NKodeCipherSuite {
|
|||||||
|
|
||||||
pub type NKodeServerSetup = ServerSetup<NKodeCipherSuite, PrivateKey<Ristretto255>, OprfSeed<Sha512>>;
|
pub type NKodeServerSetup = ServerSetup<NKodeCipherSuite, PrivateKey<Ristretto255>, OprfSeed<Sha512>>;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
||||||
pub struct RegisterSession {
|
pub struct RegisterSession {
|
||||||
|
#[get = "pub"]
|
||||||
response: RegistrationResponse<NKodeCipherSuite>,
|
response: RegistrationResponse<NKodeCipherSuite>,
|
||||||
|
#[get = "pub"]
|
||||||
session_id: Uuid
|
session_id: Uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
type PasswordFile = GenericArray<u8, RegistrationUploadLen<NKodeCipherSuite>>;
|
pub type PasswordFile = GenericArray<u8, RegistrationUploadLen<NKodeCipherSuite>>;
|
||||||
|
|
||||||
|
|
||||||
pub async fn register_secret_key<R,S>(
|
pub async fn register_secret_key<R,S>(
|
||||||
@@ -48,8 +53,11 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
||||||
pub struct LoginSession {
|
pub struct LoginSession {
|
||||||
|
#[get = "pub"]
|
||||||
response: CredentialResponse<NKodeCipherSuite>,
|
response: CredentialResponse<NKodeCipherSuite>,
|
||||||
|
#[get = "pub"]
|
||||||
session_id: Uuid
|
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");
|
server.finish(&server_response.session_id, client_finish.message).await.expect("server secret key login to finish");
|
||||||
Ok(client_finish.session_key.to_vec())
|
Ok(client_finish.session_key.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Repo {}
|
pub trait Repo {}
|
||||||
pub trait Sessions {}
|
pub trait Sessions {}
|
||||||
|
|
||||||
|
|||||||
117
src/server.rs
Normal file
117
src/server.rs
Normal file
@@ -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<PasswordFile, AuthRepoError>;
|
||||||
|
fn get_code_passcode_file(email: String) -> Result<PasswordFile, AuthRepoError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RegSession;
|
||||||
|
struct LoginSession;
|
||||||
|
|
||||||
|
trait AuthSession {
|
||||||
|
fn new_reg_session(identifier: &[u8], request: &RegistrationRequest<NKodeCipherSuite>) -> Result<RegSession, String>;
|
||||||
|
fn get_reg_session(session_id: Uuid) -> Result<RegSession, String>;
|
||||||
|
fn new_login_session(identifier: &[u8], request: &CredentialRequest<NKodeCipherSuite>) -> Result<LoginSession, String>;
|
||||||
|
fn get_login_session(session_id: Uuid) -> Result<LoginSession, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OpaqueAuth<State,R: AuthRepo, S: AuthSession> {
|
||||||
|
user_repo: R,
|
||||||
|
session: S,
|
||||||
|
_state: PhantomData<State>
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KeyAuthRegistration;
|
||||||
|
impl<R: AuthRepo,S: AuthSession> OpaqueAuth<KeyAuthRegistration, R, S>
|
||||||
|
{
|
||||||
|
async fn start(
|
||||||
|
&mut self,
|
||||||
|
identifier: &[u8],
|
||||||
|
message: &RegistrationRequest<NKodeCipherSuite>
|
||||||
|
) -> Result<RegSession, String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
password_file: PasswordFile,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KeyAuthLogin;
|
||||||
|
impl<R: AuthRepo,S: AuthSession> OpaqueAuth<KeyAuthLogin, R, S>
|
||||||
|
{
|
||||||
|
async fn start(
|
||||||
|
&mut self,
|
||||||
|
identifier: &[u8],
|
||||||
|
request_bytes: &CredentialRequest<NKodeCipherSuite>
|
||||||
|
) -> Result<LoginSession, String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
message: &CredentialFinalization<NKodeCipherSuite>
|
||||||
|
) -> Result<(), String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CodeAuthRegistration;
|
||||||
|
impl<R: AuthRepo,S: AuthSession> OpaqueAuth<CodeAuthRegistration, R, S>
|
||||||
|
{
|
||||||
|
async fn start(
|
||||||
|
&mut self,
|
||||||
|
identifier: &[u8],
|
||||||
|
message: &RegistrationRequest<NKodeCipherSuite>
|
||||||
|
) -> Result<RegSession, String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
password_file: PasswordFile,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CodeAuthLogin;
|
||||||
|
impl<R: AuthRepo,S: AuthSession> OpaqueAuth<CodeAuthLogin, R, S>
|
||||||
|
{
|
||||||
|
async fn start(
|
||||||
|
&mut self,
|
||||||
|
identifier: &[u8],
|
||||||
|
request_bytes: &CredentialRequest<NKodeCipherSuite>
|
||||||
|
) -> Result<LoginSession, String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finish(
|
||||||
|
&mut self,
|
||||||
|
session_id: &Uuid,
|
||||||
|
message: &CredentialFinalization<NKodeCipherSuite>
|
||||||
|
) -> Result<(), String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user