2020-06-05 09:35:14 -07:00
|
|
|
// 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::{
|
2020-06-14 23:25:31 -07:00
|
|
|
ciphersuite::CipherSuite,
|
2020-06-05 09:35:14 -07:00
|
|
|
errors::*,
|
|
|
|
|
group::Group,
|
|
|
|
|
key_exchange::NONCE_LEN,
|
2020-07-02 12:24:53 -07:00
|
|
|
keypair::{Key, KeyPair, X25519KeyPair},
|
2020-06-05 09:35:14 -07:00
|
|
|
opaque::*,
|
2020-07-02 12:24:53 -07:00
|
|
|
slow_hash::NoOpHash,
|
2020-06-05 09:35:14 -07:00
|
|
|
tests::mock_rng::CycleRng,
|
|
|
|
|
};
|
|
|
|
|
use curve25519_dalek::edwards::EdwardsPoint;
|
|
|
|
|
use rand_core::{OsRng, RngCore};
|
|
|
|
|
use serde_json::Value;
|
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
|
|
|
|
|
// Tests
|
|
|
|
|
// =====
|
|
|
|
|
|
2020-07-02 12:24:53 -07:00
|
|
|
struct X255193dhNoSlowHash;
|
|
|
|
|
impl CipherSuite for X255193dhNoSlowHash {
|
2020-07-03 18:28:33 -04:00
|
|
|
type Digest = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
type Group = EdwardsPoint;
|
2020-07-02 12:24:53 -07:00
|
|
|
type KeyFormat = X25519KeyPair;
|
|
|
|
|
type SlowHash = NoOpHash;
|
2020-06-14 23:25:31 -07:00
|
|
|
}
|
|
|
|
|
|
2020-06-05 09:35:14 -07:00
|
|
|
pub struct TestVectorParameters {
|
|
|
|
|
pub client_s_pk: Vec<u8>,
|
|
|
|
|
pub client_s_sk: Vec<u8>,
|
|
|
|
|
pub client_e_pk: Vec<u8>,
|
|
|
|
|
pub client_e_sk: Vec<u8>,
|
|
|
|
|
pub server_s_pk: Vec<u8>,
|
|
|
|
|
pub server_s_sk: Vec<u8>,
|
|
|
|
|
pub server_e_pk: Vec<u8>,
|
|
|
|
|
pub server_e_sk: Vec<u8>,
|
|
|
|
|
pub password: Vec<u8>,
|
|
|
|
|
pub blinding_factor_raw: Vec<u8>,
|
|
|
|
|
pub blinding_factor: Vec<u8>,
|
|
|
|
|
pub pepper: Vec<u8>,
|
|
|
|
|
pub oprf_key: Vec<u8>,
|
|
|
|
|
pub envelope_nonce: Vec<u8>,
|
|
|
|
|
pub client_nonce: Vec<u8>,
|
|
|
|
|
pub server_nonce: Vec<u8>,
|
|
|
|
|
pub r1: Vec<u8>,
|
|
|
|
|
pub r2: Vec<u8>,
|
|
|
|
|
pub r3: Vec<u8>,
|
|
|
|
|
pub l1: Vec<u8>,
|
|
|
|
|
pub l2: Vec<u8>,
|
|
|
|
|
pub l3: Vec<u8>,
|
|
|
|
|
client_registration_state: Vec<u8>,
|
|
|
|
|
server_registration_state: Vec<u8>,
|
|
|
|
|
client_login_state: Vec<u8>,
|
|
|
|
|
server_login_state: Vec<u8>,
|
|
|
|
|
pub password_file: Vec<u8>,
|
|
|
|
|
pub opaque_key: Vec<u8>,
|
|
|
|
|
pub shared_secret: Vec<u8>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static TEST_VECTOR: &str = r#"
|
|
|
|
|
{
|
2020-07-02 12:24:53 -07:00
|
|
|
"client_s_pk": "4374a0bf4f5f4353c20337574bdc69e6cff18a36e3fd8fe89fe47e02bab06e37",
|
|
|
|
|
"client_s_sk": "f0804c53de3fce8c9a6bcccb3380a1427c578a2f834de89fc98447c322776955",
|
|
|
|
|
"client_e_pk": "b45316eaa2d87ac1ed5c28b54ed43578fc54d4beb673b748159cea7536215819",
|
|
|
|
|
"client_e_sk": "60ff0381b8d8e6913d75e7a3caf2ede4e755d33337a6d904239fa6b00338cb56",
|
|
|
|
|
"server_s_pk": "c76f269ba1e0fb19597907ddd9e0fc9a4ac11e499e77b5ae480deb825dc2e044",
|
|
|
|
|
"server_s_sk": "384e6efd4236c76e7e84ae13327b867d85881f27df7f65e409c66a8f1f2c8354",
|
|
|
|
|
"server_e_pk": "92d4883730b19e767fc2f8224dac4a913f404e6d05a9baaf1f34ec9078dfb648",
|
|
|
|
|
"server_e_sk": "e88a6ec8d5644b66c20d6a915a94b27a17787196ab9f9bc0ee600d11d739b576",
|
2020-06-05 09:35:14 -07:00
|
|
|
"password": "70617373776f7264",
|
2020-07-02 12:24:53 -07:00
|
|
|
"blinding_factor_raw": "0412c9968a8e6ea19dd42eca36c35ff784d6e83944d833bdb919f8af6166ce00b742fe149fb6d9ba7d130edc983802bf91b510157d221e800e76c3aed1740159",
|
|
|
|
|
"blinding_factor": "0c9957936385474a1862bc9da3d60d6655b030fd6fc8de1fc7842163007f5a03",
|
2020-06-05 09:35:14 -07:00
|
|
|
"pepper": "706570706572",
|
2020-07-02 12:24:53 -07:00
|
|
|
"oprf_key": "764fc3396026a513ede0332f2d0801b7c02516241b473362844a9aea613e3800",
|
|
|
|
|
"envelope_nonce": "acca14c1d5f7f5843812ad61",
|
|
|
|
|
"client_nonce": "db2c06ad77d6d6b73170cb26c082c3fea77c64201b021f3d22f477bd5fd4cf9b",
|
|
|
|
|
"server_nonce": "861dbe0a824fc9a6ebc90a798dd5827888c30c8f8f79c361fb487db5b9a65586",
|
|
|
|
|
"r1": "3b12967295493838ce743c3fa5e3da39d13589aacad2cb67792df9e99dbefff3",
|
|
|
|
|
"r2": "4cce303b33ed400fc60cdaa9d314021c9a9a1c29faab56ede9fc580bdb0287c3",
|
|
|
|
|
"r3": "acca14c1d5f7f5843812ad61f0804c53de3fce8c9a6bcccb3380a1427c578a2f4df43147c5396441be3dee47f441e6cb56eca2cf7e25cc94ef233b2f1d3b0e64142d3d40fc61226627bca32c331dc00b9e9e795a1cfb0377d3a79f565307e1074374a0bf4f5f4353c20337574bdc69e6cff18a36e3fd8fe89fe47e02bab06e37",
|
|
|
|
|
"l1": "3b12967295493838ce743c3fa5e3da39d13589aacad2cb67792df9e99dbefff3db2c06ad77d6d6b73170cb26c082c3fea77c64201b021f3d22f477bd5fd4cf9bb45316eaa2d87ac1ed5c28b54ed43578fc54d4beb673b748159cea7536215819",
|
|
|
|
|
"l2": "4cce303b33ed400fc60cdaa9d314021c9a9a1c29faab56ede9fc580bdb0287c3acca14c1d5f7f5843812ad61f0804c53de3fce8c9a6bcccb3380a1427c578a2f4df43147c5396441be3dee47f441e6cb56eca2cf7e25cc94ef233b2f1d3b0e64142d3d40fc61226627bca32c331dc00b9e9e795a1cfb0377d3a79f565307e107e88a6ec8d5644b66c20d6a915a94b27a17787196ab9f9bc0ee600d11d739b57692d4883730b19e767fc2f8224dac4a913f404e6d05a9baaf1f34ec9078dfb648c87b63566267c0941b269f8ad36228ae24a2cd9eb8f90e8f6bc26140c2f93bb4",
|
|
|
|
|
"l3": "a20bb3efbdbccb23cd6206ef0483cf52a1e3b2f700c4c9aac0c9bab2f4326265",
|
|
|
|
|
"client_registration_state": "0c9957936385474a1862bc9da3d60d6655b030fd6fc8de1fc7842163007f5a0370617373776f7264",
|
|
|
|
|
"client_login_state": "0c9957936385474a1862bc9da3d60d6655b030fd6fc8de1fc7842163007f5a0360ff0381b8d8e6913d75e7a3caf2ede4e755d33337a6d904239fa6b00338cb56db2c06ad77d6d6b73170cb26c082c3fea77c64201b021f3d22f477bd5fd4cf9bb898ccd56020538145fc2192532bde9f8da0183a1dc486ae3086aa3b72c6728570617373776f7264",
|
|
|
|
|
"server_registration_state": "764fc3396026a513ede0332f2d0801b7c02516241b473362844a9aea613e3800",
|
|
|
|
|
"server_login_state": "75780c16fc843510e2222f195859b3f84c224e378f6afc6685827c30c11add9c3435530551d074a98f30d8e0f078efde0693738808a2c6358a4d34b64004a6c544b77d404067257aab5829b59a5f8a306c586c5a73018a9837c8b9a33d9fed6e",
|
|
|
|
|
"password_file": "764fc3396026a513ede0332f2d0801b7c02516241b473362844a9aea613e38004374a0bf4f5f4353c20337574bdc69e6cff18a36e3fd8fe89fe47e02bab06e37acca14c1d5f7f5843812ad61f0804c53de3fce8c9a6bcccb3380a1427c578a2f4df43147c5396441be3dee47f441e6cb56eca2cf7e25cc94ef233b2f1d3b0e64142d3d40fc61226627bca32c331dc00b9e9e795a1cfb0377d3a79f565307e107",
|
|
|
|
|
"opaque_key": "653ec91b97e928868c8977b4339530a5c1298dd9c69f1a1752a56785eca6e82c",
|
|
|
|
|
"shared_secret": "44b77d404067257aab5829b59a5f8a306c586c5a73018a9837c8b9a33d9fed6e"
|
2020-06-05 09:35:14 -07:00
|
|
|
}
|
|
|
|
|
"#;
|
|
|
|
|
|
|
|
|
|
fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
|
|
|
|
|
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(),
|
|
|
|
|
password: decode(&values, "password").unwrap(),
|
|
|
|
|
blinding_factor_raw: decode(&values, "blinding_factor_raw").unwrap(),
|
|
|
|
|
blinding_factor: decode(&values, "blinding_factor").unwrap(),
|
|
|
|
|
pepper: decode(&values, "pepper").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(),
|
|
|
|
|
r1: decode(&values, "r1").unwrap(),
|
|
|
|
|
r2: decode(&values, "r2").unwrap(),
|
|
|
|
|
r3: decode(&values, "r3").unwrap(),
|
|
|
|
|
l1: decode(&values, "l1").unwrap(),
|
|
|
|
|
l2: decode(&values, "l2").unwrap(),
|
|
|
|
|
l3: decode(&values, "l3").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(),
|
|
|
|
|
opaque_key: decode(&values, "opaque_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!("\"password\": \"{}\",\n", hex::encode(&p.password)).as_str());
|
|
|
|
|
s.push_str(
|
|
|
|
|
format!(
|
|
|
|
|
"\"blinding_factor_raw\": \"{}\",\n",
|
|
|
|
|
hex::encode(&p.blinding_factor_raw)
|
|
|
|
|
)
|
|
|
|
|
.as_str(),
|
|
|
|
|
);
|
|
|
|
|
s.push_str(
|
|
|
|
|
format!(
|
|
|
|
|
"\"blinding_factor\": \"{}\",\n",
|
|
|
|
|
hex::encode(&p.blinding_factor)
|
|
|
|
|
)
|
|
|
|
|
.as_str(),
|
|
|
|
|
);
|
|
|
|
|
s.push_str(format!("\"pepper\": \"{}\",\n", hex::encode(&p.pepper)).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!("\"r1\": \"{}\",\n", hex::encode(&p.r1)).as_str());
|
|
|
|
|
s.push_str(format!("\"r2\": \"{}\",\n", hex::encode(&p.r2)).as_str());
|
|
|
|
|
s.push_str(format!("\"r3\": \"{}\",\n", hex::encode(&p.r3)).as_str());
|
|
|
|
|
s.push_str(format!("\"l1\": \"{}\",\n", hex::encode(&p.l1)).as_str());
|
|
|
|
|
s.push_str(format!("\"l2\": \"{}\",\n", hex::encode(&p.l2)).as_str());
|
|
|
|
|
s.push_str(format!("\"l3\": \"{}\",\n", hex::encode(&p.l3)).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!("\"opaque_key\": \"{}\",\n", hex::encode(&p.opaque_key)).as_str());
|
|
|
|
|
s.push_str(format!("\"shared_secret\": \"{}\"\n", hex::encode(&p.shared_secret)).as_str());
|
|
|
|
|
s.push_str("}\n");
|
|
|
|
|
s
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-02 12:24:53 -07:00
|
|
|
fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
|
2020-06-05 09:35:14 -07:00
|
|
|
let mut rng = OsRng;
|
|
|
|
|
|
|
|
|
|
// Inputs
|
2020-07-02 12:24:53 -07:00
|
|
|
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();
|
2020-06-05 09:35:14 -07:00
|
|
|
let password = b"password";
|
|
|
|
|
let pepper = b"pepper";
|
|
|
|
|
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; 12];
|
|
|
|
|
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 mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_raw.to_vec());
|
2020-07-02 12:24:53 -07:00
|
|
|
let (r1, client_registration) = ClientRegistration::<CS>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
password,
|
|
|
|
|
Some(pepper),
|
|
|
|
|
&mut blinding_factor_registration_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let r1_bytes = r1.to_bytes().to_vec();
|
2020-07-03 17:08:29 -04:00
|
|
|
let blinding_factor_bytes = *CS::Group::scalar_as_bytes(&client_registration.blinding_factor);
|
2020-06-05 09:35:14 -07:00
|
|
|
let client_registration_state = client_registration.to_bytes().to_vec();
|
|
|
|
|
|
|
|
|
|
let mut oprf_key_rng = CycleRng::new(oprf_key_raw.to_vec());
|
2020-07-02 12:24:53 -07:00
|
|
|
let (r2, server_registration) = ServerRegistration::<CS>::start(r1, &mut oprf_key_rng).unwrap();
|
2020-06-05 09:35:14 -07:00
|
|
|
let r2_bytes = r2.to_bytes().to_vec();
|
2020-07-03 17:08:29 -04:00
|
|
|
let oprf_key_bytes = *CS::Group::scalar_as_bytes(&server_registration.oprf_key);
|
2020-06-05 09:35:14 -07:00
|
|
|
let server_registration_state = server_registration.to_bytes().to_vec();
|
|
|
|
|
|
|
|
|
|
let mut client_s_sk_and_nonce: Vec<u8> = Vec::new();
|
|
|
|
|
client_s_sk_and_nonce.extend_from_slice(&client_s_kp.private());
|
|
|
|
|
client_s_sk_and_nonce.extend_from_slice(&envelope_nonce);
|
|
|
|
|
|
|
|
|
|
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
|
|
|
|
|
let (r3, opaque_key_registration) = client_registration
|
2020-06-14 23:25:31 -07:00
|
|
|
.finish(r2, server_s_kp.public(), &mut finish_registration_rng)
|
2020-06-05 09:35:14 -07:00
|
|
|
.unwrap();
|
|
|
|
|
let r3_bytes = r3.to_bytes().to_vec();
|
|
|
|
|
|
|
|
|
|
let password_file = server_registration.finish(r3).unwrap();
|
|
|
|
|
let password_file_bytes = password_file.to_bytes();
|
|
|
|
|
|
|
|
|
|
let mut client_login_start: Vec<u8> = Vec::new();
|
|
|
|
|
client_login_start.extend_from_slice(&blinding_factor_raw);
|
|
|
|
|
client_login_start.extend_from_slice(&client_e_kp.private());
|
|
|
|
|
client_login_start.extend_from_slice(&client_nonce);
|
|
|
|
|
|
|
|
|
|
let mut client_login_start_rng = CycleRng::new(client_login_start);
|
2020-07-02 12:24:53 -07:00
|
|
|
let (l1, client_login) =
|
|
|
|
|
ClientLogin::<CS>::start(password, Some(pepper), &mut client_login_start_rng).unwrap();
|
2020-06-05 09:35:14 -07:00
|
|
|
let l1_bytes = l1.to_bytes().to_vec();
|
|
|
|
|
let client_login_state = client_login.to_bytes().to_vec();
|
|
|
|
|
|
|
|
|
|
let mut server_e_sk_rng = CycleRng::new(server_e_kp.private().to_vec());
|
|
|
|
|
let (l2, server_login) = ServerLogin::start(
|
|
|
|
|
password_file,
|
|
|
|
|
server_s_kp.private(),
|
|
|
|
|
l1,
|
|
|
|
|
&mut server_e_sk_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let l2_bytes = l2.to_bytes().to_vec();
|
|
|
|
|
let server_login_state = server_login.to_bytes().to_vec();
|
|
|
|
|
|
|
|
|
|
let mut client_e_sk_rng = CycleRng::new(client_e_kp.private().to_vec());
|
|
|
|
|
let (l3, client_shared_secret, _opaque_key_login) = client_login
|
2020-06-14 23:25:31 -07:00
|
|
|
.finish(l2, server_s_kp.public(), &mut client_e_sk_rng)
|
2020-06-05 09:35:14 -07:00
|
|
|
.unwrap();
|
|
|
|
|
let l3_bytes = l3.to_bytes().to_vec();
|
|
|
|
|
|
|
|
|
|
TestVectorParameters {
|
|
|
|
|
client_s_pk: client_s_kp.public().to_vec(),
|
|
|
|
|
client_s_sk: client_s_kp.private().to_vec(),
|
|
|
|
|
client_e_pk: client_e_kp.public().to_vec(),
|
|
|
|
|
client_e_sk: client_e_kp.private().to_vec(),
|
|
|
|
|
server_s_pk: server_s_kp.public().to_vec(),
|
|
|
|
|
server_s_sk: server_s_kp.private().to_vec(),
|
|
|
|
|
server_e_pk: server_e_kp.public().to_vec(),
|
|
|
|
|
server_e_sk: server_e_kp.private().to_vec(),
|
|
|
|
|
password: password.to_vec(),
|
|
|
|
|
blinding_factor_raw: blinding_factor_raw.to_vec(),
|
|
|
|
|
blinding_factor: blinding_factor_bytes.to_vec(),
|
|
|
|
|
pepper: pepper.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(),
|
|
|
|
|
r1: r1_bytes,
|
|
|
|
|
r2: r2_bytes,
|
|
|
|
|
r3: r3_bytes,
|
|
|
|
|
l1: l1_bytes,
|
|
|
|
|
l2: l2_bytes,
|
|
|
|
|
l3: l3_bytes,
|
|
|
|
|
password_file: password_file_bytes,
|
|
|
|
|
client_registration_state,
|
|
|
|
|
server_registration_state,
|
|
|
|
|
client_login_state,
|
|
|
|
|
server_login_state,
|
|
|
|
|
shared_secret: client_shared_secret,
|
|
|
|
|
opaque_key: opaque_key_registration.to_vec(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn generate_test_vectors() {
|
2020-07-02 12:24:53 -07:00
|
|
|
let parameters = generate_parameters::<X255193dhNoSlowHash>();
|
2020-06-05 09:35:14 -07:00
|
|
|
println!("{}", stringify_test_vectors(¶meters));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_r1() -> Result<(), PakeError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
let mut blinding_factor_rng = CycleRng::new(parameters.blinding_factor_raw);
|
2020-07-02 12:24:53 -07:00
|
|
|
let (r1, client_registration) = ClientRegistration::<X255193dhNoSlowHash>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
¶meters.password,
|
|
|
|
|
Some(¶meters.pepper),
|
|
|
|
|
&mut blinding_factor_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(hex::encode(¶meters.r1), hex::encode(r1.to_bytes()));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(¶meters.client_registration_state),
|
|
|
|
|
hex::encode(client_registration.to_bytes())
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_r2() -> Result<(), PakeError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
let mut oprf_key_rng = CycleRng::new(parameters.oprf_key);
|
2020-07-02 12:24:53 -07:00
|
|
|
let (r2, server_registration) = ServerRegistration::<X255193dhNoSlowHash>::start(
|
2020-06-14 23:25:31 -07:00
|
|
|
RegisterFirstMessage::try_from(¶meters.r1[..]).unwrap(),
|
|
|
|
|
&mut oprf_key_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
2020-06-05 09:35:14 -07:00
|
|
|
assert_eq!(hex::encode(parameters.r2), hex::encode(r2.to_bytes()));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(¶meters.server_registration_state),
|
|
|
|
|
hex::encode(server_registration.to_bytes())
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_r3() -> Result<(), PakeError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
|
|
|
|
|
let client_s_sk_and_nonce: Vec<u8> =
|
|
|
|
|
[parameters.client_s_sk, parameters.envelope_nonce].concat();
|
|
|
|
|
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
|
2020-07-02 12:24:53 -07:00
|
|
|
let (r3, opaque_key_registration) = ClientRegistration::<X255193dhNoSlowHash>::try_from(
|
2020-06-05 09:35:14 -07:00
|
|
|
¶meters.client_registration_state[..],
|
|
|
|
|
)
|
|
|
|
|
.unwrap()
|
2020-06-14 23:25:31 -07:00
|
|
|
.finish(
|
2020-06-05 09:35:14 -07:00
|
|
|
RegisterSecondMessage::try_from(¶meters.r2[..]).unwrap(),
|
2020-06-19 11:42:16 -04:00
|
|
|
&Key::try_from(¶meters.server_s_pk[..]).unwrap(),
|
2020-06-05 09:35:14 -07:00
|
|
|
&mut finish_registration_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(hex::encode(parameters.r3), hex::encode(r3.to_bytes()));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(parameters.opaque_key),
|
|
|
|
|
hex::encode(opaque_key_registration.to_vec())
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_password_file() -> Result<(), PakeError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
|
2020-07-02 12:24:53 -07:00
|
|
|
let server_registration = ServerRegistration::<X255193dhNoSlowHash>::try_from(
|
2020-06-14 23:25:31 -07:00
|
|
|
¶meters.server_registration_state[..],
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
2020-06-05 09:35:14 -07:00
|
|
|
let password_file = server_registration
|
|
|
|
|
.finish(RegisterThirdMessage::try_from(¶meters.r3[..]).unwrap())
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(parameters.password_file),
|
|
|
|
|
hex::encode(password_file.to_bytes())
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_l1() -> Result<(), PakeError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
|
|
|
|
|
let client_login_start = [
|
|
|
|
|
parameters.blinding_factor_raw,
|
|
|
|
|
parameters.client_e_sk,
|
|
|
|
|
parameters.client_nonce,
|
|
|
|
|
]
|
|
|
|
|
.concat();
|
|
|
|
|
let mut client_login_start_rng = CycleRng::new(client_login_start);
|
2020-07-02 12:24:53 -07:00
|
|
|
let (l1, client_login) = ClientLogin::<X255193dhNoSlowHash>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
¶meters.password,
|
|
|
|
|
Some(¶meters.pepper),
|
|
|
|
|
&mut client_login_start_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(hex::encode(¶meters.l1), hex::encode(l1.to_bytes()));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(¶meters.client_login_state),
|
|
|
|
|
hex::encode(client_login.to_bytes())
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_l2() -> Result<(), PakeError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
|
|
|
|
|
let mut server_e_sk_rng = CycleRng::new(parameters.server_e_sk);
|
2020-07-02 12:24:53 -07:00
|
|
|
let (l2, server_login) = ServerLogin::start::<X255193dhNoSlowHash, _>(
|
2020-06-05 09:35:14 -07:00
|
|
|
ServerRegistration::try_from(¶meters.password_file[..]).unwrap(),
|
2020-06-19 11:42:16 -04:00
|
|
|
&Key::try_from(¶meters.server_s_sk[..]).unwrap(),
|
2020-06-05 09:35:14 -07:00
|
|
|
LoginFirstMessage::<EdwardsPoint>::try_from(¶meters.l1[..]).unwrap(),
|
|
|
|
|
&mut server_e_sk_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(hex::encode(¶meters.l2), hex::encode(l2.to_bytes()));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(¶meters.server_login_state),
|
|
|
|
|
hex::encode(server_login.to_bytes())
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_l3() -> Result<(), PakeError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
|
|
|
|
|
let mut client_e_sk_rng = CycleRng::new(parameters.client_e_sk.to_vec());
|
|
|
|
|
let (l3, shared_secret, opaque_key_login) =
|
2020-07-02 12:24:53 -07:00
|
|
|
ClientLogin::<X255193dhNoSlowHash>::try_from(¶meters.client_login_state[..])
|
2020-06-14 23:25:31 -07:00
|
|
|
.unwrap()
|
|
|
|
|
.finish(
|
2020-07-02 12:24:53 -07:00
|
|
|
LoginSecondMessage::<EdwardsPoint, X25519KeyPair>::try_from(¶meters.l2[..])
|
2020-06-14 23:25:31 -07:00
|
|
|
.unwrap(),
|
2020-06-19 11:42:16 -04:00
|
|
|
&Key::try_from(¶meters.server_s_pk[..])?,
|
2020-06-14 23:25:31 -07:00
|
|
|
&mut client_e_sk_rng,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
2020-06-05 09:35:14 -07:00
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(¶meters.shared_secret),
|
|
|
|
|
hex::encode(&shared_secret)
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(hex::encode(¶meters.l3), hex::encode(l3.to_bytes()));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(¶meters.opaque_key),
|
|
|
|
|
hex::encode(opaque_key_login)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_server_login_finish() -> Result<(), ProtocolError> {
|
|
|
|
|
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
|
|
|
|
|
|
|
|
|
|
let shared_secret = ServerLogin::try_from(¶meters.server_login_state[..])
|
|
|
|
|
.unwrap()
|
|
|
|
|
.finish(LoginThirdMessage::try_from(¶meters.l3[..])?)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(parameters.shared_secret),
|
|
|
|
|
hex::encode(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;
|
2020-07-02 12:24:53 -07:00
|
|
|
let server_kp = X255193dhNoSlowHash::generate_random_keypair(&mut server_rng)?;
|
|
|
|
|
let (register_m1, client_state) = ClientRegistration::<X255193dhNoSlowHash>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
registration_password,
|
|
|
|
|
None,
|
|
|
|
|
&mut client_rng,
|
|
|
|
|
)?;
|
|
|
|
|
let (register_m2, server_state) =
|
2020-07-02 12:24:53 -07:00
|
|
|
ServerRegistration::<X255193dhNoSlowHash>::start(register_m1, &mut server_rng)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
let (register_m3, registration_opaque_key) =
|
2020-06-14 23:25:31 -07:00
|
|
|
client_state.finish(register_m2, server_kp.public(), &mut client_rng)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
let p_file = server_state.finish(register_m3)?;
|
|
|
|
|
let (login_m1, client_login_state) =
|
2020-07-02 12:24:53 -07:00
|
|
|
ClientLogin::<X255193dhNoSlowHash>::start(login_password, None, &mut client_rng)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
let (login_m2, server_login_state) =
|
|
|
|
|
ServerLogin::start(p_file, &server_kp.private(), login_m1, &mut server_rng)?;
|
|
|
|
|
|
|
|
|
|
let client_login_result =
|
2020-06-14 23:25:31 -07:00
|
|
|
client_login_state.finish(login_m2, &server_kp.public(), &mut client_rng);
|
2020-06-05 09:35:14 -07:00
|
|
|
|
|
|
|
|
if hex::encode(registration_password) == hex::encode(login_password) {
|
|
|
|
|
let (login_m3, client_shared_secret, login_opaque_key) = client_login_result?;
|
|
|
|
|
let server_shared_secret = server_login_state.finish(login_m3)?;
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(server_shared_secret),
|
|
|
|
|
hex::encode(client_shared_secret)
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
hex::encode(registration_opaque_key),
|
|
|
|
|
hex::encode(login_opaque_key)
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
let res = match client_login_result {
|
|
|
|
|
Err(ProtocolError::VerificationError(PakeError::InvalidLoginError)) => true,
|
|
|
|
|
_ => false,
|
|
|
|
|
};
|
|
|
|
|
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")
|
|
|
|
|
}
|