// Copyright (c) Meta Platforms, Inc. and affiliates. // // This source code is dual-licensed under either the MIT license found in the // LICENSE-MIT file in the root directory of this source tree or the Apache // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. You may select, at your option, one of the above-listed // licenses. #![allow(unsafe_code)] use core::ops::Add; use std::string::String; use std::vec::Vec; use std::{format, println, ptr, vec}; use digest::Output; use generic_array::typenum::{Sum, Unsigned}; use generic_array::ArrayLength; use rand::rngs::OsRng; use serde_json::Value; use subtle::ConstantTimeEq; use voprf::Group; use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash}; use crate::envelope::EnvelopeLen; use crate::errors::*; use crate::hash::OutputSize; use crate::key_exchange::group::KeGroup; use crate::key_exchange::traits::{Ke1MessageLen, Ke1StateLen, Ke2MessageLen}; use crate::key_exchange::tripledh::{DiffieHellman, NonceLen, TripleDh}; use crate::ksf::Identity; use crate::messages::{ CredentialRequestLen, CredentialResponseLen, CredentialResponseWithoutKeLen, RegistrationResponseLen, RegistrationUploadLen, }; use crate::opaque::*; use crate::tests::mock_rng::CycleRng; use crate::*; // Tests // ===== #[cfg(feature = "ristretto255")] struct Ristretto255; #[cfg(feature = "ristretto255")] impl CipherSuite for Ristretto255 { type OprfCs = crate::Ristretto255; type KeGroup = crate::Ristretto255; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "ristretto255")] struct Ristretto255P256; #[cfg(feature = "ristretto255")] impl CipherSuite for Ristretto255P256 { type OprfCs = p256::NistP256; type KeGroup = crate::Ristretto255; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "ristretto255")] struct Ristretto255P384; #[cfg(feature = "ristretto255")] impl CipherSuite for Ristretto255P384 { type OprfCs = p384::NistP384; type KeGroup = crate::Ristretto255; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "ristretto255")] struct Ristretto255P521; #[cfg(feature = "ristretto255")] impl CipherSuite for Ristretto255P521 { type OprfCs = p521::NistP521; type KeGroup = crate::Ristretto255; type KeyExchange = TripleDh; type Ksf = Identity; } struct P256; impl CipherSuite for P256 { type OprfCs = p256::NistP256; type KeGroup = p256::NistP256; type KeyExchange = TripleDh; type Ksf = Identity; } struct P256P384; impl CipherSuite for P256P384 { type OprfCs = p384::NistP384; type KeGroup = p256::NistP256; type KeyExchange = TripleDh; type Ksf = Identity; } struct P256P521; impl CipherSuite for P256P521 { type OprfCs = p521::NistP521; type KeGroup = p256::NistP256; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "ristretto255")] struct P256Ristretto255; #[cfg(feature = "ristretto255")] impl CipherSuite for P256Ristretto255 { type OprfCs = crate::Ristretto255; type KeGroup = p256::NistP256; type KeyExchange = TripleDh; type Ksf = Identity; } struct P384; impl CipherSuite for P384 { type OprfCs = p384::NistP384; type KeGroup = p384::NistP384; type KeyExchange = TripleDh; type Ksf = Identity; } struct P384P256; impl CipherSuite for P384P256 { type OprfCs = p256::NistP256; type KeGroup = p384::NistP384; type KeyExchange = TripleDh; type Ksf = Identity; } struct P384P521; impl CipherSuite for P384P521 { type OprfCs = p521::NistP521; type KeGroup = p384::NistP384; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "ristretto255")] struct P384Ristretto255; #[cfg(feature = "ristretto255")] impl CipherSuite for P384Ristretto255 { type OprfCs = crate::Ristretto255; type KeGroup = p384::NistP384; type KeyExchange = TripleDh; type Ksf = Identity; } struct P521; impl CipherSuite for P521 { type OprfCs = p521::NistP521; type KeGroup = p521::NistP521; type KeyExchange = TripleDh; type Ksf = Identity; } struct P521P256; impl CipherSuite for P521P256 { type OprfCs = p256::NistP256; type KeGroup = p521::NistP521; type KeyExchange = TripleDh; type Ksf = Identity; } struct P521P384; impl CipherSuite for P521P384 { type OprfCs = p384::NistP384; type KeGroup = p521::NistP521; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "ristretto255")] struct P521Ristretto255; #[cfg(feature = "ristretto255")] impl CipherSuite for P521Ristretto255 { type OprfCs = crate::Ristretto255; type KeGroup = p521::NistP521; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(all(feature = "curve25519", feature = "ristretto255"))] struct Curve25519Ristretto255; #[cfg(all(feature = "curve25519", feature = "ristretto255"))] impl CipherSuite for Curve25519Ristretto255 { type OprfCs = crate::Ristretto255; type KeGroup = crate::Curve25519; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "curve25519")] struct Curve25519P256; #[cfg(feature = "curve25519")] impl CipherSuite for Curve25519P256 { type OprfCs = p256::NistP256; type KeGroup = crate::Curve25519; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "curve25519")] struct Curve25519P384; #[cfg(feature = "curve25519")] impl CipherSuite for Curve25519P384 { type OprfCs = p384::NistP384; type KeGroup = crate::Curve25519; type KeyExchange = TripleDh; type Ksf = Identity; } #[cfg(feature = "curve25519")] struct Curve25519P521; #[cfg(feature = "curve25519")] impl CipherSuite for Curve25519P521 { type OprfCs = p521::NistP521; type KeGroup = crate::Curve25519; type KeyExchange = TripleDh; type Ksf = Identity; } pub struct TestVectorParameters { pub client_s_pk: Vec, pub client_s_sk: Vec, pub client_e_pk: Vec, pub client_e_sk: Vec, pub server_s_pk: Vec, pub server_s_sk: Vec, pub server_e_pk: Vec, pub server_e_sk: Vec, pub fake_sk: Vec, pub credential_identifier: Vec, pub id_u: Vec, pub id_s: Vec, pub password: Vec, pub blinding_factor: Vec, pub oprf_seed: Vec, pub masking_nonce: Vec, pub envelope_nonce: Vec, pub client_nonce: Vec, pub server_nonce: Vec, pub context: Vec, pub registration_request: Vec, pub registration_response: Vec, pub registration_upload: Vec, pub credential_request: Vec, pub credential_response: Vec, pub credential_finalization: Vec, client_registration_state: Vec, client_login_state: Vec, server_login_state: Vec, pub password_file: Vec, pub export_key: Vec, pub session_key: Vec, } static STR_PASSWORD: &str = "password"; static STR_CREDENTIAL_IDENTIFIER: &str = "credential_identifier"; macro_rules! run_all { ($name:ident $(, $par:expr)*) => { use super::full_test_vectors; #[cfg(feature = "ristretto255")] $name::(full_test_vectors::TEST_VECTOR_RISTRETTO255 $(, $par)*)?; #[cfg(feature = "ristretto255")] $name::(full_test_vectors::TEST_VECTOR_RISTRETTO255_P256 $(, $par)*)?; #[cfg(feature = "ristretto255")] $name::(full_test_vectors::TEST_VECTOR_RISTRETTO255_P384 $(, $par)*)?; #[cfg(feature = "ristretto255")] $name::(full_test_vectors::TEST_VECTOR_RISTRETTO255_P521 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P256 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P256_P384 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P256_P521 $(, $par)*)?; #[cfg(feature = "ristretto255")] $name::(full_test_vectors::TEST_VECTOR_P256_RISTRETTO255 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P384 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P384_P256 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P384_P521 $(, $par)*)?; #[cfg(feature = "ristretto255")] $name::(full_test_vectors::TEST_VECTOR_P384_RISTRETTO255 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P521 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P521_P256 $(, $par)*)?; $name::(full_test_vectors::TEST_VECTOR_P521_P384 $(, $par)*)?; #[cfg(feature = "ristretto255")] $name::(full_test_vectors::TEST_VECTOR_P521_RISTRETTO255 $(, $par)*)?; #[cfg(feature = "curve25519")] $name::(full_test_vectors::TEST_VECTOR_CURVE25519_P256 $(, $par)*)?; #[cfg(feature = "curve25519")] $name::(full_test_vectors::TEST_VECTOR_CURVE25519_P384 $(, $par)*)?; #[cfg(feature = "curve25519")] $name::(full_test_vectors::TEST_VECTOR_CURVE25519_P521 $(, $par)*)?; #[cfg(all(feature = "curve25519", feature = "ristretto255"))] $name::(full_test_vectors::TEST_VECTOR_CURVE25519_RISTRETTO255 $(, $par)*)?; }; } fn decode(values: &Value, key: &str) -> Option> { values[key].as_str().and_then(|s| hex::decode(s).ok()) } fn populate_test_vectors(values: &Value) -> TestVectorParameters { TestVectorParameters { client_s_pk: decode(values, "client_s_pk").unwrap(), client_s_sk: decode(values, "client_s_sk").unwrap(), client_e_pk: decode(values, "client_e_pk").unwrap(), client_e_sk: decode(values, "client_e_sk").unwrap(), server_s_pk: decode(values, "server_s_pk").unwrap(), server_s_sk: decode(values, "server_s_sk").unwrap(), server_e_pk: decode(values, "server_e_pk").unwrap(), server_e_sk: decode(values, "server_e_sk").unwrap(), fake_sk: decode(values, "fake_sk").unwrap(), credential_identifier: decode(values, "credential_identifier").unwrap(), id_u: decode(values, "id_u").unwrap(), id_s: decode(values, "id_s").unwrap(), password: decode(values, "password").unwrap(), blinding_factor: decode(values, "blinding_factor").unwrap(), oprf_seed: decode(values, "oprf_seed").unwrap(), masking_nonce: decode(values, "masking_nonce").unwrap(), envelope_nonce: decode(values, "envelope_nonce").unwrap(), client_nonce: decode(values, "client_nonce").unwrap(), server_nonce: decode(values, "server_nonce").unwrap(), context: decode(values, "context").unwrap(), registration_request: decode(values, "registration_request").unwrap(), registration_response: decode(values, "registration_response").unwrap(), registration_upload: decode(values, "registration_upload").unwrap(), credential_request: decode(values, "credential_request").unwrap(), credential_response: decode(values, "credential_response").unwrap(), credential_finalization: decode(values, "credential_finalization").unwrap(), client_registration_state: decode(values, "client_registration_state").unwrap(), client_login_state: decode(values, "client_login_state").unwrap(), server_login_state: decode(values, "server_login_state").unwrap(), password_file: decode(values, "password_file").unwrap(), export_key: decode(values, "export_key").unwrap(), session_key: decode(values, "session_key").unwrap(), } } fn stringify_test_vectors(p: &TestVectorParameters) -> String { let mut s = String::new(); s.push_str("{\n"); s.push_str( format!( " \"client_s_pk\": \"{}\",\n", hex::encode(&p.client_s_pk) ) .as_str(), ); s.push_str( format!( " \"client_s_sk\": \"{}\",\n", hex::encode(&p.client_s_sk) ) .as_str(), ); s.push_str( format!( " \"client_e_pk\": \"{}\",\n", hex::encode(&p.client_e_pk) ) .as_str(), ); s.push_str( format!( " \"client_e_sk\": \"{}\",\n", hex::encode(&p.client_e_sk) ) .as_str(), ); s.push_str( format!( " \"server_s_pk\": \"{}\",\n", hex::encode(&p.server_s_pk) ) .as_str(), ); s.push_str( format!( " \"server_s_sk\": \"{}\",\n", hex::encode(&p.server_s_sk) ) .as_str(), ); s.push_str( format!( " \"server_e_pk\": \"{}\",\n", hex::encode(&p.server_e_pk) ) .as_str(), ); s.push_str( format!( " \"server_e_sk\": \"{}\",\n", hex::encode(&p.server_e_sk) ) .as_str(), ); s.push_str(format!(" \"fake_sk\": \"{}\",\n", hex::encode(&p.fake_sk)).as_str()); s.push_str( format!( " \"credential_identifier\": \"{}\",\n", hex::encode(&p.credential_identifier) ) .as_str(), ); s.push_str(format!(" \"id_u\": \"{}\",\n", hex::encode(&p.id_u)).as_str()); s.push_str(format!(" \"id_s\": \"{}\",\n", hex::encode(&p.id_s)).as_str()); s.push_str(format!(" \"password\": \"{}\",\n", hex::encode(&p.password)).as_str()); s.push_str( format!( " \"blinding_factor\": \"{}\",\n", hex::encode(&p.blinding_factor) ) .as_str(), ); s.push_str(format!(" \"oprf_seed\": \"{}\",\n", hex::encode(&p.oprf_seed)).as_str()); s.push_str( format!( " \"masking_nonce\": \"{}\",\n", hex::encode(&p.masking_nonce) ) .as_str(), ); s.push_str( format!( " \"envelope_nonce\": \"{}\",\n", hex::encode(&p.envelope_nonce) ) .as_str(), ); s.push_str( format!( " \"client_nonce\": \"{}\",\n", hex::encode(&p.client_nonce) ) .as_str(), ); s.push_str( format!( " \"server_nonce\": \"{}\",\n", hex::encode(&p.server_nonce) ) .as_str(), ); s.push_str(format!(" \"context\": \"{}\",\n", hex::encode(&p.context)).as_str()); s.push_str( format!( " \"registration_request\": \"{}\",\n", hex::encode(&p.registration_request) ) .as_str(), ); s.push_str( format!( " \"registration_response\": \"{}\",\n", hex::encode(&p.registration_response) ) .as_str(), ); s.push_str( format!( " \"registration_upload\": \"{}\",\n", hex::encode(&p.registration_upload) ) .as_str(), ); s.push_str( format!( " \"credential_request\": \"{}\",\n", hex::encode(&p.credential_request) ) .as_str(), ); s.push_str( format!( " \"credential_response\": \"{}\",\n", hex::encode(&p.credential_response) ) .as_str(), ); s.push_str( format!( " \"credential_finalization\": \"{}\",\n", hex::encode(&p.credential_finalization) ) .as_str(), ); s.push_str( format!( " \"client_registration_state\": \"{}\",\n", hex::encode(&p.client_registration_state) ) .as_str(), ); s.push_str( format!( " \"client_login_state\": \"{}\",\n", hex::encode(&p.client_login_state) ) .as_str(), ); s.push_str( format!( " \"server_login_state\": \"{}\",\n", hex::encode(&p.server_login_state) ) .as_str(), ); s.push_str( format!( " \"password_file\": \"{}\",\n", hex::encode(&p.password_file) ) .as_str(), ); s.push_str(format!(" \"export_key\": \"{}\",\n", hex::encode(&p.export_key)).as_str()); s.push_str(format!(" \"session_key\": \"{}\"\n", hex::encode(&p.session_key)).as_str()); s.push_str("}\n"); s } fn generate_parameters() -> Result where // ClientRegistration: KgSk + KgPk as Group>::ScalarLen: Add< as Group>::ElemLen>, ClientRegistrationLen: ArrayLength, // RegistrationResponse: KgPk + KePk as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, // Envelope: Nonce + Hash NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope ::PkLen: Add>>, Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload // Ke1Message: Nonce + KePk NonceLen: Add<::PkLen>, Ke1MessageLen: ArrayLength, // CredentialRequest: KgPk + Ke1Message as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State as Group>::ScalarLen: Add>, Sum< as Group>::ScalarLen, CredentialRequestLen>: ArrayLength + Add>, ClientLoginLen: ArrayLength, // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as Group>::ElemLen: Add, Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // Ke2Message: (Nonce + KePk) + Hash NonceLen: Add<::PkLen>, Sum::PkLen>: ArrayLength + Add>>, Ke2MessageLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, CredentialResponseLen: ArrayLength, { use rand::RngCore; use crate::keypair::KeyPair; let mut rng = OsRng; // Inputs let server_s_kp = KeyPair::::generate_random::(&mut rng); let server_e_kp = KeyPair::::generate_random::(&mut rng); let client_s_kp = KeyPair::::generate_random::(&mut rng); let client_e_kp = KeyPair::::generate_random::(&mut rng); let fake_kp = KeyPair::::generate_random::(&mut rng); let credential_identifier = b"credIdentifier"; let id_u = b"idU"; let id_s = b"idS"; let password = b"password"; let context = b"context"; let mut oprf_seed = Output::>::default(); rng.fill_bytes(&mut oprf_seed); let mut masking_nonce = [0u8; 64]; rng.fill_bytes(&mut masking_nonce); let mut envelope_nonce = [0u8; 32]; rng.fill_bytes(&mut envelope_nonce); let mut client_nonce = [0u8; NonceLen::USIZE]; rng.fill_bytes(&mut client_nonce); let mut server_nonce = [0u8; NonceLen::USIZE]; rng.fill_bytes(&mut server_nonce); let fake_sk: Vec = fake_kp.private().serialize().to_vec(); let server_setup = ServerSetup::::deserialize( &[ oprf_seed.as_ref(), &server_s_kp.private().serialize(), &fake_sk, ] .concat(), ) .unwrap(); let blinding_factor = as Group>::random_scalar(&mut rng); let blinding_factor_bytes = OprfGroup::::serialize_scalar(blinding_factor); let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec()); let client_registration_start_result = ClientRegistration::::start(&mut blinding_factor_registration_rng, password).unwrap(); let blinding_factor_bytes_returned = OprfGroup::::serialize_scalar( client_registration_start_result .state .oprf_client .get_blind(), ); assert_eq!( hex::encode(&blinding_factor_bytes), hex::encode(&blinding_factor_bytes_returned) ); let registration_request_bytes = client_registration_start_result.message.serialize(); let client_registration_state = client_registration_start_result.state.serialize(); let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, credential_identifier, ) .unwrap(); let registration_response_bytes = server_registration_start_result.message.serialize(); let mut client_s_sk_and_nonce: Vec = Vec::new(); client_s_sk_and_nonce.extend_from_slice(&client_s_kp.private().serialize()); client_s_sk_and_nonce.extend_from_slice(&envelope_nonce); let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce); let client_registration_finish_result = client_registration_start_result .state .finish( &mut finish_registration_rng, password, server_registration_start_result.message, ClientRegistrationFinishParameters::new( Identifiers { client: Some(id_u), server: Some(id_s), }, None, ), ) .unwrap(); let registration_upload_bytes = client_registration_finish_result.message.serialize(); let password_file = ServerRegistration::finish(client_registration_finish_result.message); let password_file_bytes = password_file.serialize(); let mut client_login_start: Vec = Vec::new(); client_login_start.extend_from_slice(&blinding_factor_bytes); client_login_start.extend_from_slice(&client_e_kp.private().serialize()); client_login_start.extend_from_slice(&client_nonce); let mut client_login_start_rng = CycleRng::new(client_login_start); let client_login_start_result = ClientLogin::::start(&mut client_login_start_rng, password).unwrap(); let credential_request_bytes = client_login_start_result.message.serialize(); let client_login_state = client_login_start_result.state.serialize().to_vec(); let mut server_e_sk_and_nonce_rng = CycleRng::new( [ masking_nonce.to_vec(), server_e_kp.private().serialize().to_vec(), server_nonce.to_vec(), ] .concat(), ); let server_login_start_result = ServerLogin::::start( &mut server_e_sk_and_nonce_rng, &server_setup, Some(password_file), client_login_start_result.message, credential_identifier, ServerLoginStartParameters { context: Some(context), identifiers: Identifiers { client: Some(id_u), server: Some(id_s), }, }, ) .unwrap(); let credential_response_bytes = server_login_start_result.message.serialize(); let server_login_state = server_login_start_result.state.serialize(); let client_login_finish_result = client_login_start_result .state .finish( password, server_login_start_result.message, ClientLoginFinishParameters::new( Some(context), Identifiers { client: Some(id_u), server: Some(id_s), }, None, ), ) .unwrap(); let credential_finalization_bytes = client_login_finish_result.message.serialize(); Ok(TestVectorParameters { client_s_pk: client_s_kp.public().serialize().to_vec(), client_s_sk: client_s_kp.private().serialize().to_vec(), client_e_pk: client_e_kp.public().serialize().to_vec(), client_e_sk: client_e_kp.private().serialize().to_vec(), server_s_pk: server_s_kp.public().serialize().to_vec(), server_s_sk: server_s_kp.private().serialize().to_vec(), server_e_pk: server_e_kp.public().serialize().to_vec(), server_e_sk: server_e_kp.private().serialize().to_vec(), fake_sk, credential_identifier: credential_identifier.to_vec(), id_u: id_u.to_vec(), id_s: id_s.to_vec(), password: password.to_vec(), blinding_factor: blinding_factor_bytes.to_vec(), oprf_seed: oprf_seed.to_vec(), masking_nonce: masking_nonce.to_vec(), envelope_nonce: envelope_nonce.to_vec(), client_nonce: client_nonce.to_vec(), server_nonce: server_nonce.to_vec(), context: context.to_vec(), registration_request: registration_request_bytes.to_vec(), registration_response: registration_response_bytes.to_vec(), registration_upload: registration_upload_bytes.to_vec(), credential_request: credential_request_bytes.to_vec(), credential_response: credential_response_bytes.to_vec(), credential_finalization: credential_finalization_bytes.to_vec(), password_file: password_file_bytes.to_vec(), client_registration_state: client_registration_state.to_vec(), client_login_state, server_login_state: server_login_state.to_vec(), session_key: client_login_finish_result.session_key.to_vec(), export_key: client_registration_finish_result.export_key.to_vec(), }) } #[test] fn generate_test_vectors() -> Result<(), ProtocolError> { let mut output = String::new(); #[rustfmt::skip] output.push_str( "\ // Copyright (c) Meta Platforms, Inc. and affiliates.\n\ //\n\ // This source code is dual-licensed under either the MIT license found in the\n\ // LICENSE-MIT file in the root directory of this source tree or the Apache\n\ // License, Version 2.0 found in the LICENSE-APACHE file in the root directory\n\ // of this source tree. You may select, at your option, one of the above-listed\n\ // licenses.\n\ //\n\ // To regenerate these test vectors, run:\n\ // FULL_TEST_VECTORS_FILE=src/tests/full_test_vectors.rs cargo test --features ristretto255,curve25519 -- generate_test_vectors\n\ \n", ); #[cfg(feature = "ristretto255")] { let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"ristretto255\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_RISTRETTO255: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"ristretto255\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_RISTRETTO255_P256: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"ristretto255\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_RISTRETTO255_P384: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"ristretto255\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_RISTRETTO255_P521: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); } let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P256: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P256_P384: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P256_P521: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); #[cfg(feature = "ristretto255")] { let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"ristretto255\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_P256_RISTRETTO255: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); } let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P384: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P384_P256: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P384_P521: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); #[cfg(feature = "ristretto255")] { let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"ristretto255\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_P384_RISTRETTO255: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); } let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P521: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P521_P256: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str(&format!( "pub static TEST_VECTOR_P521_P384: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); #[cfg(feature = "ristretto255")] { let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"ristretto255\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_P521_RISTRETTO255: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); } #[cfg(feature = "curve25519")] { let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"curve25519\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_CURVE25519_P256: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"curve25519\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_CURVE25519_P384: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); let parameters = generate_parameters::()?; output.push_str("#[cfg(feature = \"curve25519\")]\n"); output.push_str(&format!( "pub static TEST_VECTOR_CURVE25519_P521: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); #[cfg(feature = "ristretto255")] { let parameters = generate_parameters::()?; output.push_str("#[cfg(all(feature = \"curve25519\", feature = \"ristretto255\"))]\n"); output.push_str(&format!( "pub static TEST_VECTOR_CURVE25519_RISTRETTO255: &str = r#\"\n{}\"#;\n", stringify_test_vectors(¶meters) )); } } if let Ok(path) = std::env::var("FULL_TEST_VECTORS_FILE") { std::fs::write(path, output).unwrap(); } else { println!("{output}"); } Ok(()) } #[test] fn test_registration_request() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where // ClientRegistration: KgSk + KgPk as Group>::ScalarLen: Add< as Group>::ElemLen>, ClientRegistrationLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let mut rng = CycleRng::new(parameters.blinding_factor.to_vec()); let client_registration_start_result = ClientRegistration::::start(&mut rng, ¶meters.password)?; assert_eq!( hex::encode(¶meters.registration_request), hex::encode(client_registration_start_result.message.serialize()) ); assert_eq!( hex::encode(¶meters.client_registration_state), hex::encode(client_registration_start_result.state.serialize()) ); Ok(()) } run_all!(inner); Ok(()) } #[cfg(feature = "serde")] #[test] fn test_serialization() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let mut rng = CycleRng::new(parameters.blinding_factor.to_vec()); let client_registration_start_result = ClientRegistration::::start(&mut rng, ¶meters.password)?; // Test the bincode serialization (binary). let registration_request = bincode::serialize(&client_registration_start_result.message).unwrap(); assert_eq!( registration_request.len(), RegistrationRequestLen::::USIZE ); let registration_request: RegistrationRequest = bincode::deserialize(®istration_request).unwrap(); assert_eq!( hex::encode(client_registration_start_result.message.serialize()), hex::encode(registration_request.serialize()), ); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_registration_response() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where // RegistrationResponse: KgPk + KePk as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, { let parameters = populate_test_vectors( &serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?, ); let server_setup = ServerSetup::::deserialize( &[ parameters.oprf_seed, parameters.server_s_sk, parameters.fake_sk, ] .concat(), )?; let server_registration_start_result = ServerRegistration::::start( &server_setup, RegistrationRequest::deserialize(¶meters.registration_request)?, ¶meters.credential_identifier, )?; assert_eq!( hex::encode(parameters.registration_response), hex::encode(server_registration_start_result.message.serialize()) ); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_registration_upload() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where // Envelope: Nonce + Hash NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope ::PkLen: Add>>, Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, { let parameters = populate_test_vectors( &serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?, ); let client_s_sk_and_nonce: Vec = [parameters.client_s_sk, parameters.envelope_nonce].concat(); let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce); let result = ClientRegistration::::deserialize(¶meters.client_registration_state)? .finish( &mut finish_registration_rng, ¶meters.password, RegistrationResponse::deserialize(¶meters.registration_response)?, ClientRegistrationFinishParameters::new( Identifiers { client: Some(¶meters.id_u), server: Some(¶meters.id_s), }, None, ), )?; assert_eq!( hex::encode(parameters.registration_upload), hex::encode(result.message.serialize()) ); assert_eq!( hex::encode(parameters.export_key), hex::encode(result.export_key) ); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_password_file() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where // Envelope: Nonce + Hash NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope ::PkLen: Add>>, Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let password_file = ServerRegistration::finish(RegistrationUpload::::deserialize( ¶meters.registration_upload, )?); assert_eq!( hex::encode(parameters.password_file), hex::encode(password_file.serialize()) ); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_credential_request() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where // CredentialRequest: KgPk + Ke1Message as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State as Group>::ScalarLen: Add>, Sum< as Group>::ScalarLen, CredentialRequestLen>: ArrayLength + Add>, ClientLoginLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let client_login_start_rng = [ parameters.blinding_factor, parameters.client_e_sk, parameters.client_nonce, ] .concat(); let mut client_login_start_rng = CycleRng::new(client_login_start_rng); let client_login_start_result = ClientLogin::::start(&mut client_login_start_rng, ¶meters.password)?; assert_eq!( hex::encode(¶meters.credential_request), hex::encode(client_login_start_result.message.serialize()) ); assert_eq!( hex::encode(¶meters.client_login_state), hex::encode(client_login_start_result.state.serialize()) ); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_credential_response() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as Group>::ElemLen: Add, Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, CredentialResponseLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let server_setup = ServerSetup::::deserialize( &[ parameters.oprf_seed, parameters.server_s_sk, parameters.fake_sk, ] .concat(), )?; let mut server_e_sk_and_nonce_rng = CycleRng::new( [ parameters.masking_nonce, parameters.server_e_sk, parameters.server_nonce, ] .concat(), ); let server_login_start_result = ServerLogin::::start( &mut server_e_sk_and_nonce_rng, &server_setup, Some(ServerRegistration::deserialize(¶meters.password_file)?), CredentialRequest::::deserialize(¶meters.credential_request)?, ¶meters.credential_identifier, ServerLoginStartParameters { context: Some(¶meters.context), identifiers: Identifiers { client: Some(¶meters.id_u), server: Some(¶meters.id_s), }, }, )?; assert_eq!( hex::encode(¶meters.credential_response), hex::encode(server_login_start_result.message.serialize()) ); assert_eq!( hex::encode(¶meters.server_login_state), hex::encode(server_login_start_result.state.serialize()) ); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_credential_finalization() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let client_login_finish_result = ClientLogin::::deserialize(¶meters.client_login_state)?.finish( ¶meters.password, CredentialResponse::::deserialize(¶meters.credential_response)?, ClientLoginFinishParameters::new( Some(¶meters.context), Identifiers { client: Some(¶meters.id_u), server: Some(¶meters.id_s), }, None, ), )?; assert_eq!( hex::encode(¶meters.server_s_pk), hex::encode(client_login_finish_result.server_s_pk.serialize()) ); assert_eq!( hex::encode(¶meters.session_key), hex::encode(&client_login_finish_result.session_key) ); assert_eq!( hex::encode(¶meters.credential_finalization), hex::encode(client_login_finish_result.message.serialize()) ); assert_eq!( hex::encode(¶meters.export_key), hex::encode(client_login_finish_result.export_key) ); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_server_login_finish() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let server_login_result = ServerLogin::::deserialize(¶meters.server_login_state)? .finish(CredentialFinalization::deserialize( ¶meters.credential_finalization, )?)?; assert_eq!( hex::encode(parameters.session_key), hex::encode(&server_login_result.session_key) ); Ok(()) } run_all!(inner); Ok(()) } fn test_complete_flow( _test_vector: &str, registration_password: &[u8], login_password: &[u8], ) -> Result<(), ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let credential_identifier = b"credentialIdentifier"; let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, registration_password)?; let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, credential_identifier, )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, registration_password, server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let p_file = ServerRegistration::finish(client_registration_finish_result.message); let client_login_start_result = ClientLogin::::start(&mut client_rng, login_password)?; let server_login_start_result = ServerLogin::::start( &mut server_rng, &server_setup, Some(p_file), client_login_start_result.message, credential_identifier, ServerLoginStartParameters::default(), )?; let client_login_result = client_login_start_result.state.finish( login_password, server_login_start_result.message, ClientLoginFinishParameters::default(), ); if hex::encode(registration_password) == hex::encode(login_password) { let client_login_finish_result = client_login_result?; let server_login_finish_result = server_login_start_result .state .finish(client_login_finish_result.message)?; assert_eq!( hex::encode(&server_login_finish_result.session_key), hex::encode(&client_login_finish_result.session_key) ); assert_eq!( hex::encode(client_registration_finish_result.export_key), hex::encode(client_login_finish_result.export_key) ); } else { assert!(matches!( client_login_result, Err(ProtocolError::InvalidLoginError) )); } Ok(()) } #[test] fn test_complete_flow_success() -> Result<(), ProtocolError> { run_all!(test_complete_flow, b"good password", b"good password"); Ok(()) } #[test] fn test_complete_flow_fail() -> Result<(), ProtocolError> { run_all!(test_complete_flow, b"good password", b"bad password"); Ok(()) } // Zeroize tests #[test] fn test_zeroize_client_registration_start() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> { let mut client_rng = OsRng; let client_registration_start_result = ClientRegistration::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let mut state = client_registration_start_result.state; unsafe { ptr::drop_in_place(&mut state) }; for byte in state.to_vec() { assert_eq!(byte, 0); } Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_zeroize_client_registration_finish() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> { let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, STR_PASSWORD.as_bytes(), server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let mut state = client_registration_finish_result.state; unsafe { ptr::drop_in_place(&mut state) }; for byte in state.to_vec() { assert_eq!(byte, 0); } Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_zeroize_server_registration_finish() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> where // Envelope: Nonce + Hash NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope ::PkLen: Add>>, Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload { let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, STR_PASSWORD.as_bytes(), server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let p_file = ServerRegistration::finish(client_registration_finish_result.message); let mut state = p_file; util::drop_manually(&mut state); util::test_zeroized(&mut state.0.envelope.mode); util::test_zeroized(&mut state.0.masking_key); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_zeroize_client_login_start() -> Result<(), ProtocolError> { fn inner>( _test_vector: &str, ) -> Result<(), ProtocolError> where ::Sk: DiffieHellman, // CredentialRequest: KgPk + Ke1Message as Group>::ElemLen: Add::PkLen>>, CredentialRequestLen: ArrayLength, // Ke1State: KeSk + Nonce ::SkLen: Add, Sum<::SkLen, NonceLen>: ArrayLength, // Ke1Message: Nonce + KePk NonceLen: Add<::PkLen>, Sum::PkLen>: ArrayLength, // Ke2State: (Hash + Hash) + Hash OutputSize>: Add>>, Sum>, OutputSize>>: ArrayLength + Add>>, Sum>, OutputSize>>, OutputSize>>: ArrayLength, // Ke2Message: (Nonce + KePk) + Hash NonceLen: Add<::PkLen>, Sum::PkLen>: ArrayLength + Add>>, Sum::PkLen>, OutputSize>>: ArrayLength, { let mut client_rng = OsRng; let client_login_start_result = ClientLogin::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let mut state = client_login_start_result.state; util::drop_manually(&mut state); util::test_zeroized(&mut state.oprf_client); util::test_zeroized(&mut state.ke1_state); util::test_zeroized(&mut state.credential_request.ke1_message.client_nonce); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_zeroize_server_login_start() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, STR_PASSWORD.as_bytes(), server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let p_file = ServerRegistration::finish(client_registration_finish_result.message); let client_login_start_result = ClientLogin::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_login_start_result = ServerLogin::::start( &mut server_rng, &server_setup, Some(p_file), client_login_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), ServerLoginStartParameters::default(), )?; let mut state = server_login_start_result.state; unsafe { ptr::drop_in_place(&mut state) }; for byte in state.serialize() { assert_eq!(byte, 0); } Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_zeroize_client_login_finish() -> Result<(), ProtocolError> { fn inner>( _test_vector: &str, ) -> Result<(), ProtocolError> where ::Sk: DiffieHellman, // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialRequest: KgPk + Ke1Message as Group>::ElemLen: Add::PkLen>>, CredentialRequestLen: ArrayLength, // Ke1State: KeSk + Nonce ::SkLen: Add, Sum<::SkLen, NonceLen>: ArrayLength, // Ke1Message: Nonce + KePk NonceLen: Add<::PkLen>, Sum::PkLen>: ArrayLength, // Ke2State: (Hash + Hash) + Hash OutputSize>: Add>>, Sum>, OutputSize>>: ArrayLength + Add>>, Sum>, OutputSize>>, OutputSize>>: ArrayLength, // Ke2Message: (Nonce + KePk) + Hash NonceLen: Add<::PkLen>, Sum::PkLen>: ArrayLength + Add>>, Sum::PkLen>, OutputSize>>: ArrayLength, { let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, STR_PASSWORD.as_bytes(), server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let p_file = ServerRegistration::finish(client_registration_finish_result.message); let client_login_start_result = ClientLogin::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_login_start_result = ServerLogin::::start( &mut server_rng, &server_setup, Some(p_file), client_login_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), ServerLoginStartParameters::default(), )?; let client_login_finish_result = client_login_start_result.state.finish( STR_PASSWORD.as_bytes(), server_login_start_result.message, ClientLoginFinishParameters::default(), )?; let mut state = client_login_finish_result.state; util::drop_manually(&mut state); util::test_zeroized(&mut state.oprf_client); util::test_zeroized(&mut state.ke1_state); util::test_zeroized(&mut state.credential_request.ke1_message.client_nonce); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_zeroize_server_login_finish() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, STR_PASSWORD.as_bytes(), server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let p_file = ServerRegistration::finish(client_registration_finish_result.message); let client_login_start_result = ClientLogin::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let server_login_start_result = ServerLogin::::start( &mut server_rng, &server_setup, Some(p_file), client_login_start_result.message, STR_CREDENTIAL_IDENTIFIER.as_bytes(), ServerLoginStartParameters::default(), )?; let client_login_finish_result = client_login_start_result.state.finish( STR_PASSWORD.as_bytes(), server_login_start_result.message, ClientLoginFinishParameters::default(), )?; let server_login_finish_result = server_login_start_result .state .finish(client_login_finish_result.message)?; let mut state = server_login_finish_result.state; unsafe { ptr::drop_in_place(&mut state) }; for byte in state.serialize() { assert_eq!(byte, 0); } Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_scalar_always_nonzero() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> { // Start out with a bunch of zeros to force resampling of scalar let mut client_registration_rng = CycleRng::new([vec![0u8; 128], vec![1u8; 128]].concat()); let client_registration_start_result = ClientRegistration::::start(&mut client_registration_rng, STR_PASSWORD.as_bytes())?; assert!(!bool::from( OprfGroup::::identity_elem().ct_eq( &client_registration_start_result .message .get_blinded_element_for_testing() .value(), ) )); // Start out with a bunch of zeros to force resampling of scalar let mut client_login_rng = CycleRng::new([vec![0u8; 128], vec![1u8; 128]].concat()); let client_login_start_result = ClientLogin::::start(&mut client_login_rng, STR_PASSWORD.as_bytes())?; assert!(!bool::from( OprfGroup::::identity_elem().ct_eq( &client_login_start_result .message .get_blinded_element_for_testing() .value(), ) )); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_reflected_value_error_registration() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> { let credential_identifier = b"credentialIdentifier"; let password = b"password"; let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, password)?; let alpha = client_registration_start_result .message .get_blinded_element_for_testing() .value(); let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, credential_identifier, )?; let reflected_registration_response = server_registration_start_result .message .set_evaluation_element_for_testing(alpha); let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, password, reflected_registration_response, ClientRegistrationFinishParameters::default(), ); assert!(matches!( client_registration_finish_result, Err(ProtocolError::ReflectedValueError) )); Ok(()) } run_all!(inner); Ok(()) } #[test] fn test_reflected_value_error_login() -> Result<(), ProtocolError> { fn inner(_test_vector: &str) -> Result<(), ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk NonceLen: Add>>, Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let credential_identifier = b"credentialIdentifier"; let password = b"password"; let mut client_rng = OsRng; let mut server_rng = OsRng; let server_setup = ServerSetup::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, password)?; let server_registration_start_result = ServerRegistration::::start( &server_setup, client_registration_start_result.message, credential_identifier, )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, password, server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let p_file = ServerRegistration::finish(client_registration_finish_result.message); let client_login_start_result = ClientLogin::::start(&mut client_rng, password)?; let alpha = client_login_start_result .message .get_blinded_element_for_testing() .value(); let server_login_start_result = ServerLogin::::start( &mut server_rng, &server_setup, Some(p_file), client_login_start_result.message, credential_identifier, ServerLoginStartParameters::default(), )?; let reflected_credential_response = server_login_start_result .message .set_evaluation_element_for_testing(alpha); let client_login_result = client_login_start_result.state.finish( password, reflected_credential_response, ClientLoginFinishParameters::default(), ); assert!(matches!( client_login_result, Err(ProtocolError::ReflectedValueError) )); Ok(()) } run_all!(inner); Ok(()) }