// Copyright (c) Facebook, Inc. and its affiliates. // // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. use crate::{ ciphersuite::CipherSuite, errors::*, group::Group, key_exchange::tripledh::{TripleDH, NONCE_LEN}, keypair::{Key, KeyPair, X25519KeyPair}, opaque::*, slow_hash::NoOpHash, tests::mock_rng::CycleRng, *, }; use curve25519_dalek::edwards::EdwardsPoint; use generic_array::GenericArray; use generic_bytes::SizedBytes; use rand_core::{OsRng, RngCore}; use serde_json::Value; use std::convert::TryFrom; // Tests // ===== struct X255193dhNoSlowHash; impl CipherSuite for X255193dhNoSlowHash { type Group = EdwardsPoint; type KeyFormat = X25519KeyPair; type KeyExchange = TripleDH; type Hash = sha2::Sha256; type SlowHash = NoOpHash; } 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 id_u: Vec, pub id_s: Vec, pub password: Vec, pub blinding_factor: Vec, pub oprf_key: Vec, pub envelope_nonce: Vec, pub client_nonce: Vec, pub server_nonce: Vec, pub info1: Vec, pub info2: Vec, pub einfo2: Vec, pub info3: Vec, pub einfo3: Vec, pub registration_request: Vec, pub registration_response: Vec, pub registration_upload: Vec, pub credential_request: Vec, pub credential_response: Vec, pub key_exchange: Vec, client_registration_state: Vec, server_registration_state: Vec, client_login_state: Vec, server_login_state: Vec, pub password_file: Vec, pub export_key: Vec, pub shared_secret: Vec, } static TEST_VECTOR: &str = r#" { "client_s_pk": "037ffc2cece49ab487448c9b52debee00bfcc72f00c78668f9b160466cc5b25a", "client_s_sk": "e09f8a22c083743c60a2eb41640dc7174edd8863bb1a7482c12a02f08914db60", "client_e_pk": "61422d4437b43abca17d2297a3b519fc37b24e20cb45d14a91ffcb1bc2107a5c", "client_e_sk": "c831faece522d77c10625d1b0ea5592fb4ee45b042b4af4218d5702b087b136e", "server_s_pk": "2cd221b189b472badcc2d4984dba174fd2e016bcc2bc8110527a11f28cd4f54f", "server_s_sk": "986f09786edea821e346bd961cc0d727d5af77f88acda9bf2f95235716535f7c", "server_e_pk": "b282307ada534fbb7e91253e8a807d3a0c5adb0cbcfb39fe5bae5bfd407abf17", "server_e_sk": "f0d994f344f79aab474637090d6aeb6319c0a8123e21a18774fb4b21496a9963", "id_u": "696455", "id_s": "696453", "password": "70617373776f7264", "blinding_factor": "26f30696f7a0d47fe3c5a08e2962880f413e805c013b59dde187df0d1667b003", "oprf_key": "b1126f88aa2377b1b56a81227c9f72c015dd6f94e1f8d88e4cb983016da50804", "envelope_nonce": "66ea20d6a122e7cb9872fd141f338c8009655963f8ba925ca801182c63921ce6", "client_nonce": "85320d740dc2d1b4e78e3c4d6e6ce474b3f2f5abe3c0e314555e310e9f5b7dde", "server_nonce": "2e1d659f03ad117e51acad7e8b8519472237aa0c7e9c35482185cefdaa972607", "info1": "696e666f31", "info2": "696e666f32", "einfo2": "65696e666f32", "info3": "696e666f33", "einfo3": "65696e666f33", "registration_request": "00205cebd79b362cbb48eab435801125e4646c4e56c9f19d720f1b7cdbca4c300ea8", "registration_response": "002075dfc31fff8a44bde1ed1fd8c9295b7516bce1fe7559692883ada956a423fa9c00202cd221b189b472badcc2d4984dba174fd2e016bcc2bc8110527a11f28cd4f54f", "registration_upload": "0166ea20d6a122e7cb9872fd141f338c8009655963f8ba925ca801182c63921ce600223c2deccbf09b5506d628137bd661b6de943a92fe762fd2b872c6adabc1e4c10ca2fb002c00202cd221b189b472badcc2d4984dba174fd2e016bcc2bc8110527a11f28cd4f54f000369645500036964530020dd6e96af9578ad04ef758070afdbb34ac695d2be131fed185ce746537cd02de60020037ffc2cece49ab487448c9b52debee00bfcc72f00c78668f9b160466cc5b25a", "credential_request": "00205cebd79b362cbb48eab435801125e4646c4e56c9f19d720f1b7cdbca4c300ea885320d740dc2d1b4e78e3c4d6e6ce474b3f2f5abe3c0e314555e310e9f5b7dde0005696e666f3161422d4437b43abca17d2297a3b519fc37b24e20cb45d14a91ffcb1bc2107a5c", "credential_response": "002075dfc31fff8a44bde1ed1fd8c9295b7516bce1fe7559692883ada956a423fa9c00202cd221b189b472badcc2d4984dba174fd2e016bcc2bc8110527a11f28cd4f54f0166ea20d6a122e7cb9872fd141f338c8009655963f8ba925ca801182c63921ce600223c2deccbf09b5506d628137bd661b6de943a92fe762fd2b872c6adabc1e4c10ca2fb002c00202cd221b189b472badcc2d4984dba174fd2e016bcc2bc8110527a11f28cd4f54f000369645500036964530020dd6e96af9578ad04ef758070afdbb34ac695d2be131fed185ce746537cd02de6f0d994f344f79aab474637090d6aeb6319c0a8123e21a18774fb4b21496a99630005696e666f32b282307ada534fbb7e91253e8a807d3a0c5adb0cbcfb39fe5bae5bfd407abf17000665696e666f32fb98272619ab5c17b860c2a59f194b88203080f641b96c278d10d69be004d2dd", "key_exchange": "0005696e666f33000665696e666f33a13c4265ac30d7e079e975a550571ee95e74149cdc83b8683ac12d3764ed779a", "client_registration_state": "26f30696f7a0d47fe3c5a08e2962880f413e805c013b59dde187df0d1667b00370617373776f7264", "client_login_state": "26f30696f7a0d47fe3c5a08e2962880f413e805c013b59dde187df0d1667b003c831faece522d77c10625d1b0ea5592fb4ee45b042b4af4218d5702b087b136e85320d740dc2d1b4e78e3c4d6e6ce474b3f2f5abe3c0e314555e310e9f5b7dde518be4c0634f9829245f95c3ead10fafa41c29be9c6ca976bff9a1a22a61895e70617373776f7264", "server_registration_state": "b1126f88aa2377b1b56a81227c9f72c015dd6f94e1f8d88e4cb983016da50804", "server_login_state": "cb5e5021406dab84937ee7964c288e2ea176f7533ef12c2f7836dfc0a034c0387088884ba8e2ed9703ebf185a91511426d4dff480bd7282057e49b0b0fc38d6fa58f4c40f986833c2773696694d51a0a36d9ee85b0aacfc9cdad34dd9ad90d61", "password_file": "b1126f88aa2377b1b56a81227c9f72c015dd6f94e1f8d88e4cb983016da50804037ffc2cece49ab487448c9b52debee00bfcc72f00c78668f9b160466cc5b25a0166ea20d6a122e7cb9872fd141f338c8009655963f8ba925ca801182c63921ce600223c2deccbf09b5506d628137bd661b6de943a92fe762fd2b872c6adabc1e4c10ca2fb002c00202cd221b189b472badcc2d4984dba174fd2e016bcc2bc8110527a11f28cd4f54f000369645500036964530020dd6e96af9578ad04ef758070afdbb34ac695d2be131fed185ce746537cd02de6", "export_key": "776947002cb41ad575506e82778313bb8d2767dd9d7ed3fd55f875071d833a2e", "shared_secret": "a58f4c40f986833c2773696694d51a0a36d9ee85b0aacfc9cdad34dd9ad90d61" } "#; fn decode(values: &Value, key: &str) -> Option> { values[key] .as_str() .and_then(|s| hex::decode(&s.to_string()).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(), 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_key: decode(&values, "oprf_key").unwrap(), envelope_nonce: decode(&values, "envelope_nonce").unwrap(), client_nonce: decode(&values, "client_nonce").unwrap(), server_nonce: decode(&values, "server_nonce").unwrap(), info1: decode(&values, "info1").unwrap(), info2: decode(&values, "info2").unwrap(), einfo2: decode(&values, "einfo2").unwrap(), info3: decode(&values, "info3").unwrap(), einfo3: decode(&values, "einfo3").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(), key_exchange: decode(&values, "key_exchange").unwrap(), client_registration_state: decode(&values, "client_registration_state").unwrap(), client_login_state: decode(&values, "client_login_state").unwrap(), server_registration_state: decode(&values, "server_registration_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(), shared_secret: decode(&values, "shared_secret").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!("\"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_key\": \"{}\",\n", hex::encode(&p.oprf_key)).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!("\"info1\": \"{}\",\n", hex::encode(&p.info1)).as_str()); s.push_str(format!("\"info2\": \"{}\",\n", hex::encode(&p.info2)).as_str()); s.push_str(format!("\"einfo2\": \"{}\",\n", hex::encode(&p.einfo2)).as_str()); s.push_str(format!("\"info3\": \"{}\",\n", hex::encode(&p.info3)).as_str()); s.push_str(format!("\"einfo3\": \"{}\",\n", hex::encode(&p.einfo3)).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!("\"key_exchange\": \"{}\",\n", hex::encode(&p.key_exchange)).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_registration_state\": \"{}\",\n", hex::encode(&p.server_registration_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!("\"shared_secret\": \"{}\"\n", hex::encode(&p.shared_secret)).as_str()); s.push_str("}\n"); s } fn generate_parameters() -> TestVectorParameters where // Unsightly constraints due to the (required) use of the SizedBytes // instance for KP in ServerRegistration::start. See also the impl // Tryfrom<&[u8]> for ServerRegistration (those are the same constraints). <::Repr as SizedBytes>::Len: std::ops::Add<<::Repr as SizedBytes>::Len>, generic_array::typenum::Sum< <::Repr as SizedBytes>::Len, <::Repr as SizedBytes>::Len, >: generic_array::ArrayLength, { let mut rng = OsRng; // Inputs let server_s_kp = CS::generate_random_keypair(&mut rng).unwrap(); let server_e_kp = CS::generate_random_keypair(&mut rng).unwrap(); let client_s_kp = CS::generate_random_keypair(&mut rng).unwrap(); let client_e_kp = CS::generate_random_keypair(&mut rng).unwrap(); let id_u = b"idU"; let id_s = b"idS"; let password = b"password"; let mut blinding_factor_raw = [0u8; 64]; rng.fill_bytes(&mut blinding_factor_raw); let mut oprf_key_raw = [0u8; 32]; rng.fill_bytes(&mut oprf_key_raw); let mut envelope_nonce = [0u8; 32]; rng.fill_bytes(&mut envelope_nonce); let mut client_nonce = [0u8; NONCE_LEN]; rng.fill_bytes(&mut client_nonce); let mut server_nonce = [0u8; NONCE_LEN]; rng.fill_bytes(&mut server_nonce); let info1 = b"info1"; let info2 = b"info2"; let einfo2 = b"einfo2"; let info3 = b"info3"; let einfo3 = b"einfo3"; let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_raw.to_vec()); let client_registration_start_result = ClientRegistration::::start( &mut blinding_factor_registration_rng, password, std::convert::identity, ) .unwrap(); let registration_request_bytes = client_registration_start_result .message .serialize() .to_vec(); let blinding_factor_bytes = CS::Group::scalar_as_bytes(&client_registration_start_result.state.token.blind).clone(); let client_registration_state = client_registration_start_result.state.to_bytes().to_vec(); let mut oprf_key_rng = CycleRng::new(oprf_key_raw.to_vec()); let server_registration_start_result = ServerRegistration::::start( &mut oprf_key_rng, client_registration_start_result.message, server_s_kp.public(), ) .unwrap(); let registration_response_bytes = server_registration_start_result .message .serialize() .to_vec(); let oprf_key_bytes = CS::Group::scalar_as_bytes(&server_registration_start_result.state.oprf_key).clone(); let server_registration_state = server_registration_start_result.state.to_bytes().to_vec(); let mut client_s_sk_and_nonce: Vec = Vec::new(); client_s_sk_and_nonce.extend_from_slice(&client_s_kp.private().to_arr()); 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, server_registration_start_result.message, ClientRegistrationFinishParameters::WithIdentifiers(id_u.to_vec(), id_s.to_vec()), ) .unwrap(); let registration_upload_bytes = client_registration_finish_result .message .serialize() .to_vec(); let password_file = server_registration_start_result .state .finish(client_registration_finish_result.message) .unwrap(); let password_file_bytes = password_file.to_bytes(); let mut client_login_start: Vec = Vec::new(); client_login_start.extend_from_slice(&blinding_factor_raw); client_login_start.extend_from_slice(&client_e_kp.private().to_arr()); 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, ClientLoginStartParameters::WithInfo(info1.to_vec()), std::convert::identity, ) .unwrap(); let credential_request_bytes = client_login_start_result.message.serialize().to_vec(); let client_login_state = client_login_start_result.state.to_bytes().to_vec(); let mut server_e_sk_rng = CycleRng::new(server_e_kp.private().to_arr().to_vec()); let server_login_start_result = ServerLogin::::start( &mut server_e_sk_rng, password_file, server_s_kp.private(), client_login_start_result.message, ServerLoginStartParameters::WithInfoAndIdentifiers( info2.to_vec(), einfo2.to_vec(), id_u.to_vec(), id_s.to_vec(), ), ) .unwrap(); let credential_response_bytes = server_login_start_result.message.serialize().to_vec(); let server_login_state = server_login_start_result.state.to_bytes().to_vec(); let client_login_finish_result = client_login_start_result .state .finish( server_login_start_result.message, ClientLoginFinishParameters::WithInfoAndIdentifiers( info3.to_vec(), einfo3.to_vec(), id_u.to_vec(), id_s.to_vec(), ), ) .unwrap(); let key_exchange_bytes = client_login_finish_result.message.to_bytes().to_vec(); TestVectorParameters { client_s_pk: client_s_kp.public().to_arr().to_vec(), client_s_sk: client_s_kp.private().to_arr().to_vec(), client_e_pk: client_e_kp.public().to_arr().to_vec(), client_e_sk: client_e_kp.private().to_arr().to_vec(), server_s_pk: server_s_kp.public().to_arr().to_vec(), server_s_sk: server_s_kp.private().to_arr().to_vec(), server_e_pk: server_e_kp.public().to_arr().to_vec(), server_e_sk: server_e_kp.private().to_arr().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_key: oprf_key_bytes.to_vec(), envelope_nonce: envelope_nonce.to_vec(), client_nonce: client_nonce.to_vec(), server_nonce: server_nonce.to_vec(), info1: info1.to_vec(), info2: info2.to_vec(), einfo2: einfo2.to_vec(), info3: info3.to_vec(), einfo3: einfo3.to_vec(), registration_request: registration_request_bytes, registration_response: registration_response_bytes, registration_upload: registration_upload_bytes, credential_request: credential_request_bytes, credential_response: credential_response_bytes, key_exchange: key_exchange_bytes, password_file: password_file_bytes, client_registration_state, server_registration_state, client_login_state, server_login_state, shared_secret: client_login_finish_result.shared_secret, export_key: client_registration_finish_result.export_key.to_vec(), } } #[test] fn generate_test_vectors() { let parameters = generate_parameters::(); println!("{}", stringify_test_vectors(¶meters)); } // For fixing the blinding factor fn postprocess_blinding_factor(_: G::Scalar) -> G::Scalar { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); G::from_scalar_slice(GenericArray::from_slice(¶meters.blinding_factor[..])).unwrap() } #[test] fn test_registration_request() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let mut rng = OsRng; let client_registration_start_result = ClientRegistration::::start( &mut rng, ¶meters.password, postprocess_blinding_factor::<::Group>, )?; 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.to_bytes()) ); Ok(()) } #[test] fn test_registration_response() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let mut oprf_key_rng = CycleRng::new(parameters.oprf_key); let server_registration_start_result = ServerRegistration::::start( &mut oprf_key_rng, RegistrationRequest::deserialize(¶meters.registration_request[..]).unwrap(), &Key::try_from(¶meters.server_s_pk[..]).unwrap(), )?; assert_eq!( hex::encode(parameters.registration_response), hex::encode(server_registration_start_result.message.serialize()) ); assert_eq!( hex::encode(¶meters.server_registration_state), hex::encode(server_registration_start_result.state.to_bytes()) ); Ok(()) } #[test] fn test_registration_upload() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); 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::::try_from( ¶meters.client_registration_state[..], )? .finish( &mut finish_registration_rng, RegistrationResponse::deserialize(¶meters.registration_response[..]).unwrap(), ClientRegistrationFinishParameters::WithIdentifiers(parameters.id_u, parameters.id_s), )?; assert_eq!( hex::encode(parameters.registration_upload), hex::encode(result.message.serialize()) ); assert_eq!( hex::encode(parameters.export_key), hex::encode(result.export_key.to_vec()) ); Ok(()) } #[test] fn test_password_file() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let server_registration = ServerRegistration::::try_from( ¶meters.server_registration_state[..], )?; let password_file = server_registration .finish(RegistrationUpload::deserialize(¶meters.registration_upload[..]).unwrap())?; assert_eq!( hex::encode(parameters.password_file), hex::encode(password_file.to_bytes()) ); Ok(()) } #[test] fn test_credential_request() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let client_login_start = [ vec![0u8; 64], // FIXME: don't hardcode this parameters.client_e_sk, parameters.client_nonce, ] .concat(); let mut client_login_start_rng = CycleRng::new(client_login_start); let client_login_start_result = ClientLogin::::start( &mut client_login_start_rng, ¶meters.password, ClientLoginStartParameters::WithInfo(parameters.info1), postprocess_blinding_factor::<::Group>, )?; 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.to_bytes()) ); Ok(()) } #[test] fn test_credential_response() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let mut server_e_sk_rng = CycleRng::new(parameters.server_e_sk); let server_login_start_result = ServerLogin::::start( &mut server_e_sk_rng, ServerRegistration::try_from(¶meters.password_file[..]).unwrap(), &Key::try_from(¶meters.server_s_sk[..]).unwrap(), CredentialRequest::::deserialize(¶meters.credential_request[..]) .unwrap(), ServerLoginStartParameters::WithInfoAndIdentifiers( parameters.info2.to_vec(), parameters.einfo2.to_vec(), parameters.id_u, parameters.id_s, ), )?; assert_eq!( hex::encode(¶meters.info1), hex::encode(server_login_start_result.plain_info), ); 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.to_bytes()) ); Ok(()) } #[test] fn test_key_exchange() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let client_login_finish_result = ClientLogin::::try_from(¶meters.client_login_state[..]) .unwrap() .finish( CredentialResponse::::deserialize( ¶meters.credential_response[..], )?, ClientLoginFinishParameters::WithInfoAndIdentifiers( parameters.info3.to_vec(), parameters.einfo3.to_vec(), parameters.id_u, parameters.id_s, ), )?; assert_eq!( hex::encode(¶meters.info2), hex::encode(&client_login_finish_result.plain_info) ); assert_eq!( hex::encode(¶meters.einfo2), hex::encode(&client_login_finish_result.confidential_info) ); assert_eq!( hex::encode(¶meters.server_s_pk), hex::encode(&client_login_finish_result.server_s_pk.to_arr().to_vec()) ); assert_eq!( hex::encode(¶meters.shared_secret), hex::encode(&client_login_finish_result.shared_secret) ); assert_eq!( hex::encode(¶meters.key_exchange), hex::encode(client_login_finish_result.message.to_bytes()) ); assert_eq!( hex::encode(¶meters.export_key), hex::encode(client_login_finish_result.export_key) ); Ok(()) } #[test] fn test_server_login_finish() -> Result<(), ProtocolError> { let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let server_login_result = ServerLogin::::try_from(¶meters.server_login_state[..])?.finish( CredentialFinalization::try_from(¶meters.key_exchange[..])?, )?; assert_eq!( hex::encode(parameters.info3), hex::encode(server_login_result.plain_info) ); assert_eq!( hex::encode(parameters.einfo3), hex::encode(server_login_result.confidential_info) ); assert_eq!( hex::encode(parameters.shared_secret), hex::encode(server_login_result.shared_secret) ); Ok(()) } fn test_complete_flow( registration_password: &[u8], login_password: &[u8], ) -> Result<(), ProtocolError> { let mut client_rng = OsRng; let mut server_rng = OsRng; let server_kp = X255193dhNoSlowHash::generate_random_keypair(&mut server_rng)?; let client_registration_start_result = ClientRegistration::::start( &mut client_rng, registration_password, std::convert::identity, )?; let server_registration_start_result = ServerRegistration::::start( &mut server_rng, client_registration_start_result.message, server_kp.public(), )?; let client_registration_finish_result = client_registration_start_result.state.finish( &mut client_rng, server_registration_start_result.message, ClientRegistrationFinishParameters::default(), )?; let p_file = server_registration_start_result .state .finish(client_registration_finish_result.message)?; let client_login_start_result = ClientLogin::::start( &mut client_rng, login_password, ClientLoginStartParameters::default(), std::convert::identity, )?; let server_login_start_result = ServerLogin::::start( &mut server_rng, p_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default(), )?; let client_login_result = client_login_start_result.state.finish( 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.shared_secret), hex::encode(client_login_finish_result.shared_secret) ); assert_eq!( hex::encode(client_registration_finish_result.export_key), hex::encode(client_login_finish_result.export_key) ); } else { let res = matches!( client_login_result, Err(ProtocolError::VerificationError( PakeError::InvalidLoginError )) ); assert!(res); } Ok(()) } #[test] fn test_complete_flow_success() -> Result<(), ProtocolError> { test_complete_flow(b"good password", b"good password") } #[test] fn test_complete_flow_fail() -> Result<(), ProtocolError> { test_complete_flow(b"good password", b"bad password") }