initial
This commit is contained in:
154
src/registration.rs
Normal file
154
src/registration.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
use rand::RngCore;
|
||||
|
||||
use crate::ake::generate_kem_keypair;
|
||||
use crate::envelope;
|
||||
use crate::error::Result;
|
||||
use crate::oprf::{BlindedElement, EvaluatedElement, OprfClient, OprfServer};
|
||||
use crate::types::{
|
||||
ClientPrivateKey, ClientPublicKey, OPRF_SEED_LEN, OprfSeed, RegistrationRecord,
|
||||
RegistrationRequest, RegistrationResponse, ServerPublicKey,
|
||||
};
|
||||
|
||||
pub struct ClientRegistrationState {
|
||||
oprf_client: OprfClient,
|
||||
}
|
||||
|
||||
pub fn client_registration_start(
|
||||
password: &[u8],
|
||||
) -> (ClientRegistrationState, RegistrationRequest) {
|
||||
let (oprf_client, blinded) = OprfClient::blind(password);
|
||||
|
||||
let request = RegistrationRequest {
|
||||
blinded_element: blinded.to_bytes(),
|
||||
};
|
||||
|
||||
let state = ClientRegistrationState { oprf_client };
|
||||
|
||||
(state, request)
|
||||
}
|
||||
|
||||
pub fn server_registration_respond(
|
||||
oprf_seed: &OprfSeed,
|
||||
request: &RegistrationRequest,
|
||||
server_public_key: &ServerPublicKey,
|
||||
credential_id: &[u8],
|
||||
) -> Result<RegistrationResponse> {
|
||||
let blinded = BlindedElement::from_bytes(&request.blinded_element)?;
|
||||
|
||||
let oprf_server = OprfServer::new(oprf_seed.clone());
|
||||
let evaluated = oprf_server.evaluate_with_credential_id(&blinded, credential_id)?;
|
||||
|
||||
Ok(RegistrationResponse {
|
||||
evaluated_element: evaluated.to_bytes(),
|
||||
server_public_key: server_public_key.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn client_registration_finish(
|
||||
state: ClientRegistrationState,
|
||||
response: &RegistrationResponse,
|
||||
server_identity: Option<&[u8]>,
|
||||
client_identity: Option<&[u8]>,
|
||||
) -> Result<RegistrationRecord> {
|
||||
let evaluated = EvaluatedElement::from_bytes(&response.evaluated_element)?;
|
||||
|
||||
let randomized_pwd = state.oprf_client.finalize(&evaluated)?;
|
||||
|
||||
let (client_kem_pk, client_kem_sk) = generate_kem_keypair();
|
||||
let client_private_key = ClientPrivateKey::new(client_kem_sk.as_bytes());
|
||||
let client_public_key = ClientPublicKey::new(client_kem_pk.as_bytes());
|
||||
|
||||
let (envelope, _, _, masking_key) = envelope::store(
|
||||
&randomized_pwd,
|
||||
&response.server_public_key,
|
||||
&client_private_key,
|
||||
server_identity,
|
||||
client_identity,
|
||||
)?;
|
||||
|
||||
Ok(RegistrationRecord {
|
||||
client_public_key,
|
||||
masking_key: masking_key.to_vec(),
|
||||
envelope,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_oprf_seed() -> OprfSeed {
|
||||
let mut bytes = [0u8; OPRF_SEED_LEN];
|
||||
rand::thread_rng().fill_bytes(&mut bytes);
|
||||
OprfSeed::new(bytes)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ake::{generate_kem_keypair, generate_sig_keypair};
|
||||
|
||||
fn create_server_keys() -> (ServerPublicKey, Vec<u8>, Vec<u8>) {
|
||||
let (kem_pk, kem_sk) = generate_kem_keypair();
|
||||
let (sig_pk, sig_sk) = generate_sig_keypair();
|
||||
let server_pk = ServerPublicKey::new(kem_pk.as_bytes(), sig_pk.as_bytes());
|
||||
(server_pk, kem_sk.as_bytes(), sig_sk.as_bytes())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_full_registration_flow() {
|
||||
let oprf_seed = generate_oprf_seed();
|
||||
let (server_pk, _, _) = create_server_keys();
|
||||
let credential_id = b"user@example.com";
|
||||
let password = b"correct horse battery staple";
|
||||
|
||||
let (client_state, request) = client_registration_start(password);
|
||||
|
||||
let response =
|
||||
server_registration_respond(&oprf_seed, &request, &server_pk, credential_id).unwrap();
|
||||
|
||||
let record = client_registration_finish(client_state, &response, None, None).unwrap();
|
||||
|
||||
assert!(!record.client_public_key.kem_pk.is_empty());
|
||||
assert!(!record.masking_key.is_empty());
|
||||
assert!(!record.envelope.auth_tag.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_registration_with_identities() {
|
||||
let oprf_seed = generate_oprf_seed();
|
||||
let (server_pk, _, _) = create_server_keys();
|
||||
let credential_id = b"user@example.com";
|
||||
let password = b"password123";
|
||||
|
||||
let (client_state, request) = client_registration_start(password);
|
||||
|
||||
let response =
|
||||
server_registration_respond(&oprf_seed, &request, &server_pk, credential_id).unwrap();
|
||||
|
||||
let record = client_registration_finish(
|
||||
client_state,
|
||||
&response,
|
||||
Some(b"server.example.com"),
|
||||
Some(b"user@example.com"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(!record.envelope.auth_tag.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_passwords_different_records() {
|
||||
let oprf_seed = generate_oprf_seed();
|
||||
let (server_pk, _, _) = create_server_keys();
|
||||
let credential_id = b"user@example.com";
|
||||
|
||||
let (client_state1, request1) = client_registration_start(b"password1");
|
||||
let response1 =
|
||||
server_registration_respond(&oprf_seed, &request1, &server_pk, credential_id).unwrap();
|
||||
let record1 = client_registration_finish(client_state1, &response1, None, None).unwrap();
|
||||
|
||||
let (client_state2, request2) = client_registration_start(b"password2");
|
||||
let response2 =
|
||||
server_registration_respond(&oprf_seed, &request2, &server_pk, credential_id).unwrap();
|
||||
let record2 = client_registration_finish(client_state2, &response2, None, None).unwrap();
|
||||
|
||||
assert_ne!(record1.envelope.auth_tag, record2.envelope.auth_tag);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user