Adding API for handling info fields (#88)

This commit is contained in:
Kevin Lewi
2020-11-16 14:05:43 -08:00
committed by GitHub
parent 51b3781e5c
commit 95152c3b35
9 changed files with 987 additions and 794 deletions
+29 -22
View File
@@ -28,13 +28,11 @@ use std::convert::TryFrom;
use std::process::exit;
use opaque_ke::{
ciphersuite::CipherSuite,
keypair::KeyPair,
opaque::{
ClientLogin, ClientRegistration, LoginFirstMessage, LoginSecondMessage, LoginThirdMessage,
RegisterFirstMessage, RegisterSecondMessage, RegisterThirdMessage, ServerLogin,
ServerRegistration,
},
ciphersuite::CipherSuite, keypair::KeyPair, ClientLogin, ClientLoginFinishParameters,
ClientLoginStartParameters, ClientRegistration, ClientRegistrationStartParameters,
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage,
RegisterSecondMessage, RegisterThirdMessage, ServerLogin, ServerLoginStartParameters,
ServerRegistration,
};
// The ciphersuite trait allows to specify the underlying primitives
@@ -55,8 +53,12 @@ fn account_registration(
password: String,
) -> Vec<u8> {
let mut client_rng = OsRng;
let (r1, client_state) =
ClientRegistration::<Default>::start(password.as_bytes(), &mut client_rng).unwrap();
let (r1, client_state) = ClientRegistration::<Default>::start(
password.as_bytes(),
ClientRegistrationStartParameters::default(),
&mut client_rng,
)
.unwrap();
let r1_bytes = r1.serialize();
// Client sends r1_bytes to server
@@ -64,6 +66,7 @@ fn account_registration(
let mut server_rng = OsRng;
let (r2, server_state) = ServerRegistration::<Default>::start(
RegisterFirstMessage::deserialize(&r1_bytes[..]).unwrap(),
server_kp.public(),
&mut server_rng,
)
.unwrap();
@@ -74,7 +77,6 @@ fn account_registration(
let (r3, _) = client_state
.finish(
RegisterSecondMessage::deserialize(&r2_bytes[..]).unwrap(),
server_kp.public(),
&mut client_rng,
)
.unwrap();
@@ -95,45 +97,50 @@ fn account_login(
password_file_bytes: &[u8],
) -> bool {
let mut client_rng = OsRng;
let (l1, client_state) =
ClientLogin::<Default>::start(password.as_bytes(), &mut client_rng).unwrap();
let l1_bytes = l1.serialize();
let client_login_start_result = ClientLogin::<Default>::start(
password.as_bytes(),
&mut client_rng,
ClientLoginStartParameters::default(),
)
.unwrap();
let l1_bytes = client_login_start_result.credential_request.serialize();
// Client sends l1_bytes to server
let password_file = ServerRegistration::<Default>::try_from(password_file_bytes).unwrap();
let mut server_rng = OsRng;
let (l2, server_state) = ServerLogin::start(
let server_login_start_result = ServerLogin::start(
password_file,
&server_kp.private(),
LoginFirstMessage::deserialize(&l1_bytes[..]).unwrap(),
&mut server_rng,
ServerLoginStartParameters::default(),
)
.unwrap();
let l2_bytes = l2.serialize();
let l2_bytes = server_login_start_result.credential_response.serialize();
// Server sends l2_bytes to client
let result = client_state.finish(
let result = client_login_start_result.client_login_state.finish(
LoginSecondMessage::deserialize(&l2_bytes[..]).unwrap(),
&server_kp.public(),
&mut client_rng,
ClientLoginFinishParameters::default(),
);
if result.is_err() {
// Client-detected login failure
return false;
}
let (l3, client_shared_secret, _) = result.unwrap();
let l3_bytes = l3.serialize();
let client_login_finish_result = result.unwrap();
let l3_bytes = client_login_finish_result.key_exchange.serialize();
// Client sends l3_bytes to server
let server_shared_secret = server_state
let server_login_finish_result = server_login_start_result
.server_login_state
.finish(LoginThirdMessage::deserialize(&l3_bytes[..]).unwrap())
.unwrap();
client_shared_secret == server_shared_secret
client_login_finish_result.session_secret == server_login_finish_result.session_secret
}
// A function run on the client which extracts a username and password from the CLI
+10 -4
View File
@@ -25,7 +25,7 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
rng: &mut R,
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>;
#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
fn generate_ke2<R: RngCore + CryptoRng>(
rng: &mut R,
l1_bytes: Vec<u8>,
@@ -33,24 +33,30 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
ke1_message: Self::KE1Message,
client_s_pk: KeyFormat::Repr,
server_s_sk: KeyFormat::Repr,
id_u: Vec<u8>,
id_s: Vec<u8>,
info: Vec<u8>,
e_info: Vec<u8>,
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError>;
) -> Result<(Vec<u8>, Self::KE2State, Self::KE2Message), ProtocolError>;
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
fn generate_ke3(
l2_component: Vec<u8>,
ke2_message: Self::KE2Message,
ke1_state: &Self::KE1State,
server_s_pk: KeyFormat::Repr,
client_s_sk: KeyFormat::Repr,
id_u: Vec<u8>,
id_s: Vec<u8>,
info: Vec<u8>,
e_info: Vec<u8>,
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError>;
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>, Self::KE3Message), ProtocolError>;
#[allow(clippy::type_complexity)]
fn finish_ke(
ke3_message: Self::KE3Message,
ke2_state: &Self::KE2State,
) -> Result<Vec<u8>, ProtocolError>;
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), ProtocolError>;
fn ke1_state_size() -> usize;
+26 -12
View File
@@ -81,6 +81,7 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
))
}
#[allow(clippy::type_complexity)]
fn generate_ke2<R: RngCore + CryptoRng>(
rng: &mut R,
l1_bytes: Vec<u8>,
@@ -88,9 +89,11 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
ke1_message: Self::KE1Message,
client_s_pk: KeyFormat::Repr,
server_s_sk: KeyFormat::Repr,
id_u: Vec<u8>,
id_s: Vec<u8>,
info: Vec<u8>,
e_info: Vec<u8>,
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError> {
) -> Result<(Vec<u8>, Self::KE2State, Self::KE2Message), ProtocolError> {
let server_e_kp = KeyFormat::generate_random(rng)?;
let server_nonce: GenericArray<u8, NonceLen> = {
let mut server_nonce_bytes = [0u8; NONCE_LEN];
@@ -103,14 +106,14 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
pk1: ke1_message.client_e_pk.clone(),
sk1: server_e_kp.private().clone(),
pk2: ke1_message.client_e_pk,
sk2: server_s_sk.clone(),
pk3: client_s_pk.clone(),
sk2: server_s_sk,
pk3: client_s_pk,
sk3: server_e_kp.private().clone(),
},
&ke1_message.client_nonce,
&server_nonce,
&client_s_pk.to_arr(),
&KeyFormat::public_from_private(&server_s_sk).to_arr(),
&id_u,
&id_s,
)?;
let mut hasher = D::new();
@@ -142,6 +145,7 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
let hashed_transcript = hasher3.finalize();
Ok((
ke1_message.info,
KE2State {
km3,
hashed_transcript,
@@ -157,28 +161,31 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
))
}
#[allow(clippy::type_complexity)]
fn generate_ke3(
l2_component: Vec<u8>,
ke2_message: Self::KE2Message,
ke1_state: &Self::KE1State,
server_s_pk: KeyFormat::Repr,
client_s_sk: KeyFormat::Repr,
id_u: Vec<u8>,
id_s: Vec<u8>,
info: Vec<u8>,
e_info: Vec<u8>,
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError> {
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>, Self::KE3Message), ProtocolError> {
let (session_secret, km2, km3) = derive_3dh_keys::<KeyFormat, D>(
TripleDHComponents {
pk1: ke2_message.server_e_pk.clone(),
sk1: ke1_state.client_e_sk.clone(),
pk2: server_s_pk.clone(),
pk2: server_s_pk,
sk2: ke1_state.client_e_sk.clone(),
pk3: ke2_message.server_e_pk.clone(),
sk3: client_s_sk.clone(),
sk3: client_s_sk,
},
&ke1_state.client_nonce,
&ke2_message.server_nonce,
&KeyFormat::public_from_private(&client_s_sk).to_arr(),
&server_s_pk.to_arr(),
&id_u,
&id_s,
)?;
let transcript: Vec<u8> = [
@@ -219,6 +226,8 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
client_mac.update(&transcript_with_ke3);
Ok((
ke2_message.info,
ke2_message.e_info, // TODO: need to decrypt
session_secret.to_vec(),
KE3Message {
info,
@@ -228,10 +237,11 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
))
}
#[allow(clippy::type_complexity)]
fn finish_ke(
ke3_message: Self::KE3Message,
ke2_state: &Self::KE2State,
) -> Result<Vec<u8>, ProtocolError> {
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), ProtocolError> {
let transcript_with_ke3 = [
ke2_state.hashed_transcript.to_vec(),
ke3_message.to_bytes_without_mac(),
@@ -247,7 +257,11 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
));
}
Ok(ke2_state.session_secret.to_vec())
Ok((
ke3_message.info,
ke3_message.e_info, // TODO: need to decrypt
ke2_state.session_secret.to_vec(),
))
}
fn ke1_state_size() -> usize {
+74 -48
View File
@@ -71,7 +71,7 @@
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::ServerRegistration,
//! # ServerRegistration,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -84,11 +84,12 @@
//! # type Hash = sha2::Sha256;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! use opaque_ke::opaque::ClientRegistration;
//! use opaque_ke::{ClientRegistration, ClientRegistrationStartParameters};
//! use rand_core::{OsRng, RngCore};
//! let mut client_rng = OsRng;
//! let (r1, client_state) = ClientRegistration::<Default>::start(
//! b"password",
//! ClientRegistrationStartParameters::default(),
//! &mut client_rng,
//! )?;
//! # Ok::<(), ProtocolError>(())
@@ -101,7 +102,7 @@
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::ClientRegistration,
//! # ClientRegistration, ClientRegistrationStartParameters,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -118,11 +119,13 @@
//! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
//! # b"password",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! use opaque_ke::opaque::ServerRegistration;
//! use opaque_ke::ServerRegistration;
//! let mut server_rng = OsRng;
//! let (r2, server_state) = ServerRegistration::<Default>::start(r1, &mut server_rng)?;
//! let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # Ok::<(), ProtocolError>(())
//! ```
//! `r2` is returned to the client, and `server_state` must be persisted on the server for the final step of server
@@ -134,7 +137,7 @@
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::{ClientRegistration, ServerRegistration},
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -151,13 +154,14 @@
//! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
//! # b"password",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, &mut server_rng)?;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! let (r3, export_key_registration) =
//! client_state.finish(r2, server_kp.public(), &mut client_rng)?;
//! client_state.finish(r2, &mut client_rng)?;
//! # Ok::<(), ProtocolError>(())
//! ```
//! `r3` is sent to the server, and the client can optionally use `export_key_registration` for applications that choose to
@@ -168,7 +172,7 @@
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::{ClientRegistration, ServerRegistration},
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -185,12 +189,13 @@
//! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
//! # b"password",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, &mut server_rng)?;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, server_kp.public(), &mut client_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?;
//! let password_file = server_state.finish(r3)?;
//! # Ok::<(), ProtocolError>(())
//! ```
@@ -210,7 +215,7 @@
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::{ClientRegistration, ServerRegistration, ServerLogin, LoginThirdMessage},
//! # ClientRegistration, ServerRegistration, ServerLogin, LoginThirdMessage,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -224,23 +229,25 @@
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
//! # }
//! # use rand_core::{OsRng, RngCore};
//! use opaque_ke::opaque::ClientLogin;
//! use opaque_ke::{ClientLogin, ClientLoginStartParameters};
//! let mut client_rng = OsRng;
//! let (l1, client_state) = ClientLogin::<Default>::start(
//! let client_login_start_result = ClientLogin::<Default>::start(
//! b"password",
//! &mut client_rng,
//! ClientLoginStartParameters::default(),
//! )?;
//! # Ok::<(), ProtocolError>(())
//! ```
//! `l1` is sent to the server, and `client_state` must be persisted on the client for the final step of client login.
//! `client_login_start_result.credential_request` is sent to the server, and `client_login_start_result.client_login_state`
//! must be persisted on the client for the final step of client login.
//!
//! In the second step (server login start), the server takes as input the `l1` message from the client, the server's
//! private key `server_kp.private()`, along with a serialized version of the password file, `password_file_bytes`, and
//! runs `ServerLogin::start` to produce `l2`:
//! runs `ServerLogin::start` to produce `server_login_start_result`:
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, LoginThirdMessage},
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, LoginThirdMessage,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -257,26 +264,29 @@
//! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
//! # b"password",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, &mut server_rng)?;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, server_kp.public(), &mut client_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
//! # let (l1, client_state) = ClientLogin::<Default>::start(
//! # let client_login_start_result = ClientLogin::<Default>::start(
//! # b"password",
//! # &mut client_rng,
//! # ClientLoginStartParameters::default(),
//! # )?;
//! use opaque_ke::opaque::ServerLogin;
//! use opaque_ke::{ServerLogin, ServerLoginStartParameters};
//! use std::convert::TryFrom;
//! let password_file = ServerRegistration::<Default>::try_from(&password_file_bytes[..])?;
//! let mut server_rng = OsRng;
//! let (l2, server_state) =
//! ServerLogin::start(password_file, &server_kp.private(), l1, &mut server_rng)?;
//! let server_login_start_result =
//! ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
//! # Ok::<(), ProtocolError>(())
//! ```
//! `l2` is returned to the client, and `server_state` must be persisted on the server for the final step of server login.
//! `server_login_start_result.credential_response` is returned to the client, and `server_login_start_result.server_login_state`
//! must be persisted on the server for the final step of server login.
//!
//! In the third step (client login finish), the client takes as input the `l2` message from the server, along with the
//! server's static public key `server_kp.public()`, and uses `client_state` from the first step to run `finish` and produce
@@ -284,7 +294,7 @@
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage},
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -301,30 +311,31 @@
//! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
//! # b"password",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, &mut server_rng)?;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, server_kp.public(), &mut client_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
//! # let (l1, client_state) = ClientLogin::<Default>::start(
//! # let client_login_start_result = ClientLogin::<Default>::start(
//! # b"password",
//! # &mut client_rng,
//! # ClientLoginStartParameters::default(),
//! # )?;
//! # use std::convert::TryFrom;
//! # let password_file =
//! # ServerRegistration::<Default>::try_from(
//! # &password_file_bytes[..],
//! # )?;
//! # let (l2, server_state) =
//! # ServerLogin::start(password_file, &server_kp.private(), l1, &mut server_rng)?;
//! let (l3, client_shared_secret, export_key_login) = client_state.finish(
//! l2,
//! &server_kp.public(),
//! &mut client_rng,
//! # let server_login_start_result =
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
//! let client_login_finish_result = client_login_start_result.client_login_state.finish(
//! server_login_start_result.credential_response,
//! ClientLoginFinishParameters::default(),
//! )?;
//! assert_eq!(export_key_registration, export_key_login);
//! assert_eq!(export_key_registration, client_login_finish_result.export_key);
//! # Ok::<(), ProtocolError>(())
//! ```
//! Note that if the client supplies a tuple (password, pepper, server public key) that does not match the tuple
@@ -339,7 +350,7 @@
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage},
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -356,31 +367,32 @@
//! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
//! # b"password",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, &mut server_rng)?;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r3, export_key) = client_state.finish(r2, server_kp.public(), &mut client_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key) = client_state.finish(r2, &mut client_rng)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
//! # let (l1, client_state) = ClientLogin::<Default>::start(
//! # let client_login_start_result = ClientLogin::<Default>::start(
//! # b"password",
//! # &mut client_rng,
//! # ClientLoginStartParameters::default(),
//! # )?;
//! # use std::convert::TryFrom;
//! # let password_file =
//! # ServerRegistration::<Default>::try_from(
//! # &password_file_bytes[..],
//! # )?;
//! # let (l2, server_state) =
//! # ServerLogin::start(password_file, &server_kp.private(), l1, &mut server_rng)?;
//! # let (l3, client_shared_secret, export_key) = client_state.finish(
//! # l2,
//! # &server_kp.public(),
//! # &mut client_rng,
//! # let server_login_start_result =
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
//! # let client_login_finish_result = client_login_start_result.client_login_state.finish(
//! # server_login_start_result.credential_response,
//! # ClientLoginFinishParameters::default(),
//! # )?;
//! let server_shared_secret = server_state.finish(l3)?;
//! assert_eq!(client_shared_secret, server_shared_secret);
//! let server_login_finish_result = server_login_start_result.server_login_state.finish(client_login_finish_result.key_exchange)?;
//! assert_eq!(client_login_finish_result.session_secret, server_login_finish_result.session_secret);
//! # Ok::<(), ProtocolError>(())
//! ```
//! If the protocol completes successfully, then the server obtains a `server_shared_secret` which is guaranteed to
@@ -400,7 +412,9 @@ compile_error!(
pub mod errors;
// High-level API
pub mod opaque;
mod opaque;
mod messages;
pub mod ciphersuite;
mod envelope;
@@ -425,3 +439,15 @@ mod serialization;
#[cfg(test)]
mod tests;
// Exports
pub use crate::messages::{
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage,
RegisterSecondMessage, RegisterThirdMessage,
};
pub use crate::opaque::{ClientLogin, ClientRegistration, ServerLogin, ServerRegistration};
pub use crate::opaque::{
ClientLoginFinishParameters, ClientLoginStartParameters, ClientRegistrationStartParameters,
ServerLoginStartParameters,
};
+471
View File
@@ -0,0 +1,471 @@
// 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.
//! Contains the messages used for OPAQUE
use crate::{
ciphersuite::CipherSuite,
envelope::{Envelope, EnvelopeCredentialsFormat},
errors::{
utils::{check_slice_size, check_slice_size_atleast},
PakeError, ProtocolError,
},
group::Group,
hash::Hash,
key_exchange::traits::{KeyExchange, ToBytes},
keypair::{KeyPair, SizedBytesExt},
serialization::{
serialize, tokenize, u8_to_credential_type, CredentialType, ProtocolMessageType,
},
};
use generic_array::{typenum::Unsigned, GenericArray};
use generic_bytes::SizedBytes;
use std::convert::TryFrom;
// Messages
// =========
/// The message sent by the client to the server, to initiate registration
pub struct RegisterFirstMessage<Grp> {
/// blinded password information
pub(crate) alpha: Grp,
}
impl<Grp: Group> TryFrom<&[u8]> for RegisterFirstMessage<Grp> {
type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let elem_len = Grp::ElemLen::to_usize();
let checked_slice = check_slice_size(first_message_bytes, elem_len, "first_message_bytes")?;
// Check that the message is actually containing an element of the
// correct subgroup
let arr = GenericArray::from_slice(&checked_slice[checked_slice.len() - elem_len..]);
let alpha = Grp::from_element_slice(arr)?;
Ok(Self { alpha })
}
}
impl<Grp: Group> RegisterFirstMessage<Grp> {
/// Byte representation for the registration request
pub fn to_bytes(&self) -> Vec<u8> {
self.alpha.to_arr().to_vec()
}
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
let mut registration_request: Vec<u8> = Vec::new();
registration_request.extend_from_slice(&serialize(&self.alpha.to_arr(), 2));
let mut output: Vec<u8> = Vec::new();
output.push(ProtocolMessageType::from(self) as u8 + 1);
output.extend_from_slice(&serialize(&registration_request, 3));
output
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
if input.is_empty()
|| input.is_empty()
|| input[0] != ProtocolMessageType::RegistrationRequest as u8 + 1
{
return Err(PakeError::SerializationError.into());
}
let (data, remainder) = tokenize(&input[1..], 3)?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
let (alpha_bytes, remainder) = tokenize(&data, 2)?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
let checked_slice = check_slice_size(
&alpha_bytes,
Grp::ElemLen::to_usize(),
"first_message_bytes",
)?;
// Check that the message is actually containing an element of the
// correct subgroup
let arr = GenericArray::from_slice(checked_slice);
let alpha = Grp::from_element_slice(arr)?;
Ok(Self { alpha })
}
}
/// The answer sent by the server to the user, upon reception of the
/// registration attempt
pub struct RegisterSecondMessage<Grp> {
/// The server's oprf output
pub(crate) beta: Grp,
/// Server's static public key
pub(crate) server_s_pk: Vec<u8>,
/// Envelope credentials format
pub(crate) ecf: EnvelopeCredentialsFormat,
}
impl<Grp> TryFrom<&[u8]> for RegisterSecondMessage<Grp>
where
Grp: Group,
{
type Error = ProtocolError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let elem_len = Grp::ElemLen::to_usize();
let checked_slice = check_slice_size_atleast(bytes, elem_len, "second_message_bytes")?;
// Check that the message is actually containing an element of the
// correct subgroup
let arr = GenericArray::from_slice(&checked_slice[..elem_len]);
let beta = Grp::from_element_slice(arr)?;
let server_s_pk = checked_slice[elem_len..].to_vec();
// Note that we use a default envelope credentials format here, since it
// is not included in the byte representation
let ecf = EnvelopeCredentialsFormat::default()?;
Ok(Self {
beta,
server_s_pk,
ecf,
})
}
}
impl<Grp> RegisterSecondMessage<Grp>
where
Grp: Group,
{
/// Byte representation for the registration response message. This does not
/// include the envelope credentials format
pub fn to_bytes(&self) -> Vec<u8> {
[&self.beta.to_arr().to_vec()[..], &self.server_s_pk[..]].concat()
}
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
let mut registration_response: Vec<u8> = Vec::new();
registration_response.extend_from_slice(&serialize(&self.beta.to_arr(), 2));
registration_response.extend_from_slice(&serialize(&self.server_s_pk, 2));
// Handle ecf serialization
let secret_credentials: Vec<u8> = self
.ecf
.secret_credentials
.iter()
.map(|&x| x as u8 + 1)
.collect();
let cleartext_credentials: Vec<u8> = self
.ecf
.cleartext_credentials
.iter()
.map(|&x| x as u8 + 1)
.collect();
let ecf_serialized = [
serialize(&secret_credentials, 1),
serialize(&cleartext_credentials, 1),
]
.concat();
registration_response.extend_from_slice(&ecf_serialized);
let mut output: Vec<u8> = Vec::new();
output.push(ProtocolMessageType::from(self) as u8 + 1);
output.extend_from_slice(&serialize(&registration_response, 3));
output
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
if input.is_empty() || input[0] != ProtocolMessageType::RegistrationResponse as u8 + 1 {
return Err(PakeError::SerializationError.into());
}
let (data, remainder) = tokenize(&input[1..], 3)?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
let (beta_bytes, remainder) = tokenize(&data, 2)?;
let (server_s_pk, remainder) = tokenize(&remainder, 2)?;
// Handle ecf deserialization
let (secret_credentials, remainder) = tokenize(&remainder, 1)?;
let (cleartext_credentials, remainder) = tokenize(&remainder, 1)?;
let sc = secret_credentials
.iter()
.map(|x| u8_to_credential_type(*x).ok_or(PakeError::SerializationError))
.collect::<Result<Vec<CredentialType>, _>>()?;
let cc = cleartext_credentials
.iter()
.map(|x| u8_to_credential_type(*x).ok_or(PakeError::SerializationError))
.collect::<Result<Vec<CredentialType>, _>>()?;
let ecf = EnvelopeCredentialsFormat::new(sc, cc)?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
let checked_slice = check_slice_size(
&beta_bytes,
Grp::ElemLen::to_usize(),
"second_message_bytes",
)?;
// Check that the message is actually containing an element of the
// correct subgroup
let arr = GenericArray::from_slice(&checked_slice);
let beta = Grp::from_element_slice(arr)?;
Ok(Self {
ecf,
server_s_pk,
beta,
})
}
}
/// The final message from the client, containing sealed cryptographic
/// identifiers
pub struct RegisterThirdMessage<KeyFormat: KeyPair, D: Hash> {
/// The "envelope" generated by the user, containing sealed
/// cryptographic identifiers
pub(crate) envelope: Envelope<D>,
/// The user's public key
pub(crate) client_s_pk: KeyFormat::Repr,
}
impl<KeyFormat, D> TryFrom<&[u8]> for RegisterThirdMessage<KeyFormat, D>
where
KeyFormat: KeyPair,
D: Hash,
{
type Error = ProtocolError;
fn try_from(third_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let key_len = <KeyFormat::Repr as SizedBytes>::Len::to_usize();
let envelope_size = key_len + Envelope::<D>::additional_size();
let checked_bytes = check_slice_size(
third_message_bytes,
envelope_size + key_len,
"third_message",
)?;
let unchecked_client_s_pk = KeyFormat::Repr::from_bytes(&checked_bytes[envelope_size..])?;
let client_s_pk = KeyFormat::check_public_key(unchecked_client_s_pk)?;
Ok(Self {
envelope: Envelope::<D>::from_bytes(&checked_bytes[..envelope_size])?,
client_s_pk,
})
}
}
impl<KeyFormat, D> RegisterThirdMessage<KeyFormat, D>
where
KeyFormat: KeyPair,
D: Hash,
{
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
let mut registration_upload: Vec<u8> = Vec::new();
registration_upload.extend_from_slice(&self.envelope.serialize());
registration_upload.extend_from_slice(&serialize(&self.client_s_pk.to_arr(), 2));
let mut output: Vec<u8> = Vec::new();
output.push(ProtocolMessageType::from(self) as u8 + 1);
output.extend_from_slice(&serialize(&registration_upload, 3));
output
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
if input.is_empty() || input[0] != ProtocolMessageType::RegistrationUpload as u8 + 1 {
return Err(PakeError::SerializationError.into());
}
let (data, remainder) = tokenize(&input[1..], 3)?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
let (envelope, remainder) = Envelope::<D>::deserialize(&data)?;
let (client_s_pk, remainder) = tokenize(&remainder, 2)?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
Ok(Self {
envelope,
client_s_pk: KeyFormat::check_public_key(KeyFormat::Repr::from_bytes(&client_s_pk)?)?,
})
}
}
/// The message sent by the user to the server, to initiate registration
pub struct LoginFirstMessage<CS: CipherSuite> {
/// blinded password information
pub(crate) alpha: CS::Group,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE1Message,
}
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> {
type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
Self::deserialize(first_message_bytes)
}
}
impl<CS: CipherSuite> LoginFirstMessage<CS> {
/// byte representation for the login request
pub(crate) fn to_bytes(&self) -> Vec<u8> {
[&self.alpha.to_arr()[..], &self.ke1_message.to_bytes()].concat()
}
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
let mut credential_request: Vec<u8> = Vec::new();
credential_request.extend_from_slice(&serialize(&self.alpha.to_arr(), 2));
let mut output: Vec<u8> = Vec::new();
output.push(ProtocolMessageType::from(self) as u8 + 1);
output.extend_from_slice(&serialize(&credential_request, 3));
output.extend_from_slice(&self.ke1_message.to_bytes());
output
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
if input.is_empty() || input[0] != ProtocolMessageType::CredentialRequest as u8 + 1 {
return Err(PakeError::SerializationError.into());
}
let (data, ke1m) = tokenize(&input[1..], 3)?;
let (alpha_bytes, remainder) = tokenize(&data, 2)?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
let elem_len = <CS::Group as Group>::ElemLen::to_usize();
let checked_slice = check_slice_size(&alpha_bytes, elem_len, "login_first_message_bytes")?;
let arr = GenericArray::from_slice(&checked_slice[..elem_len]);
let alpha = <CS::Group as Group>::from_element_slice(arr)?;
let ke1_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE1Message::try_from(
&ke1m[..],
)?;
Ok(Self { alpha, ke1_message })
}
}
/// The answer sent by the server to the user, upon reception of the
/// login attempt.
pub struct LoginSecondMessage<CS: CipherSuite> {
/// the server's oprf output
pub(crate) beta: CS::Group,
/// the user's sealed information,
pub(crate) envelope: Envelope<CS::Hash>,
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE2Message,
}
impl<CS: CipherSuite> LoginSecondMessage<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
let mut credential_response: Vec<u8> = Vec::new();
credential_response.extend_from_slice(&serialize(&self.beta.to_arr(), 2));
credential_response.extend_from_slice(&self.envelope.to_bytes());
let mut output: Vec<u8> = Vec::new();
output.push(ProtocolMessageType::from(self) as u8 + 1);
output.extend_from_slice(&serialize(&credential_response, 3));
output.extend_from_slice(&self.ke2_message.to_bytes());
output
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
if input.is_empty() || input[0] != ProtocolMessageType::CredentialResponse as u8 + 1 {
return Err(PakeError::SerializationError.into());
}
let (data, ke2m) = tokenize(&input[1..], 3)?;
let (beta_bytes, envelope_bytes) = tokenize(&data, 2)?;
let concatenated = [&beta_bytes[..], &envelope_bytes[..], &ke2m[..]].concat();
Self::try_from(&concatenated[..])
}
}
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginSecondMessage<CS> {
type Error = ProtocolError;
fn try_from(second_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize();
let checked_slice =
check_slice_size_atleast(second_message_bytes, elem_len, "login_second_message_bytes")?;
// Check that the message is actually containing an element of the
// correct subgroup
let beta_bytes = &checked_slice[..elem_len];
let arr = GenericArray::from_slice(beta_bytes);
let beta = CS::Group::from_element_slice(arr)?;
let (envelope, remainder) = Envelope::<CS::Hash>::deserialize(&checked_slice[elem_len..])?;
let ke2_message_size = CS::KeyExchange::ke2_message_size();
let checked_remainder =
check_slice_size_atleast(&remainder, ke2_message_size, "login_second_message_bytes")?;
let ke2_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE2Message::try_from(
&checked_remainder,
)?;
Ok(Self {
beta,
envelope,
ke2_message,
})
}
}
/// The answer sent by the client to the server, upon reception of the
/// sealed envelope
pub struct LoginThirdMessage<CS: CipherSuite> {
pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE3Message,
}
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginThirdMessage<CS> {
type Error = ProtocolError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let ke3_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE3Message::try_from(bytes)?;
Ok(Self { ke3_message })
}
}
impl<CS: CipherSuite> LoginThirdMessage<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
let mut output: Vec<u8> = Vec::new();
output.push(ProtocolMessageType::from(self) as u8 + 1);
output.extend_from_slice(&self.ke3_message.to_bytes());
output
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
if input.is_empty() || input[0] != ProtocolMessageType::KeyExchange as u8 + 1 {
return Err(PakeError::SerializationError.into());
}
Self::try_from(&input[1..])
}
/// byte representation for the login finalization
pub fn to_bytes(&self) -> Vec<u8> {
self.ke3_message.to_bytes()
}
}
+262 -634
View File
File diff suppressed because it is too large Load Diff
+2 -7
View File
@@ -6,13 +6,8 @@
use crate::errors::PakeError;
use crate::{
ciphersuite::CipherSuite,
hash::Hash,
keypair::KeyPair,
opaque::{
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage,
RegisterSecondMessage, RegisterThirdMessage,
},
ciphersuite::CipherSuite, hash::Hash, keypair::KeyPair, LoginFirstMessage, LoginSecondMessage,
LoginThirdMessage, RegisterFirstMessage, RegisterSecondMessage, RegisterThirdMessage,
};
pub enum ProtocolMessageType {
+1
View File
@@ -14,6 +14,7 @@ use crate::{
keypair::{KeyPair, X25519KeyPair},
opaque::*,
serialization::{i2osp, os2ip, serialize, ProtocolMessageType},
*,
};
use curve25519_dalek::ristretto::RistrettoPoint;
+112 -67
View File
@@ -12,6 +12,7 @@ use crate::{
opaque::*,
slow_hash::NoOpHash,
tests::mock_rng::CycleRng,
*,
};
use curve25519_dalek::edwards::EdwardsPoint;
use generic_array::GenericArray;
@@ -83,7 +84,7 @@ static TEST_VECTOR: &str = r#"
"client_nonce": "8bdd8689f4ea9486aaa3bac182d31f31e3c62d76b3869ae1dd05d5c708b13e86",
"server_nonce": "d529ed9480524236ed6f6cafd92ebab3c6091afde54f47f9079575c090cad7d6",
"r1": "010000220020ada5910d73be53a8a6c50d32e9efcc0eb3e871103c05fb993fcb8312aff7fc79",
"r2": "02000028002035104271fe25c0074ea715af805c019772a97b6e975376f411e1c37831a56fa7000001010103",
"r2": "02000048002035104271fe25c0074ea715af805c019772a97b6e975376f411e1c37831a56fa700209ef0646ad66cf13ce4052294c7325e044853f0c1fd03e91288f8339d812d4a5701010103",
"r3": "030000aeb326061dfc120f5b261b28bbae4262c26ad343a640b5fb4b90ba3f16600e1c89002375ba1dad2970f60479c4ce0fe1e62271f2c5561757557c88941d9278ededbc981de07c00230300209ef0646ad66cf13ce4052294c7325e044853f0c1fd03e91288f8339d812d4a570020c575cad080bafce229c0de9700269d48d8102d3f0f70497a770d9c0bcb5d181e0020aee30cf198cc78b5b1a5ed5a4bda21bceb5e4732fffbddf867e32ee814d67317",
"l1": "040000220020ada5910d73be53a8a6c50d32e9efcc0eb3e871103c05fb993fcb8312aff7fc798bdd8689f4ea9486aaa3bac182d31f31e3c62d76b3869ae1dd05d5c708b13e8600001fb90ca40034a0ee0d9d087a2c12743329d792b21e4c4424e561a665a1031b00",
"l2": "050000ae002035104271fe25c0074ea715af805c019772a97b6e975376f411e1c37831a56fa7b326061dfc120f5b261b28bbae4262c26ad343a640b5fb4b90ba3f16600e1c89002375ba1dad2970f60479c4ce0fe1e62271f2c5561757557c88941d9278ededbc981de07c00230300209ef0646ad66cf13ce4052294c7325e044853f0c1fd03e91288f8339d812d4a570020c575cad080bafce229c0de9700269d48d8102d3f0f70497a770d9c0bcb5d181ef021332310d7f6a1c8272d11610e0244cf462efe1a7d9e6657cf12f74d30f2720000b2df778b631c83d1fdd76feb9978d156ad0c1d18fedbe2b15a309f673e3d846400003bc4221316aaad7b6110910bae5a3bc0e498738634916021546f6fce652adc78",
@@ -250,10 +251,9 @@ where
rng.fill_bytes(&mut server_nonce);
let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_raw.to_vec());
let (r1, client_registration) = ClientRegistration::<CS>::start_with_user_and_server_name(
id_u,
id_s,
let (r1, client_registration) = ClientRegistration::<CS>::start(
password,
ClientRegistrationStartParameters::WithIdentifiers(id_u.to_vec(), id_s.to_vec()),
&mut blinding_factor_registration_rng,
std::convert::identity,
)
@@ -264,7 +264,8 @@ where
let client_registration_state = client_registration.to_bytes().to_vec();
let mut oprf_key_rng = CycleRng::new(oprf_key_raw.to_vec());
let (r2, server_registration) = ServerRegistration::<CS>::start(r1, &mut oprf_key_rng).unwrap();
let (r2, server_registration) =
ServerRegistration::<CS>::start(r1, server_s_kp.public(), &mut oprf_key_rng).unwrap();
let r2_bytes = r2.serialize().to_vec();
let oprf_key_bytes = CS::Group::scalar_as_bytes(&server_registration.oprf_key).clone();
let server_registration_state = server_registration.to_bytes().to_vec();
@@ -275,7 +276,7 @@ where
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
let (r3, export_key_registration) = client_registration
.finish(r2, server_s_kp.public(), &mut finish_registration_rng)
.finish(r2, &mut finish_registration_rng)
.unwrap();
let r3_bytes = r3.serialize().to_vec();
@@ -288,33 +289,52 @@ where
client_login_start.extend_from_slice(&client_nonce);
let mut client_login_start_rng = CycleRng::new(client_login_start);
let (l1, client_login) = ClientLogin::<CS>::start_with_user_and_server_name(
id_u,
id_s,
let client_login_start_result = ClientLogin::<CS>::start(
password,
&mut client_login_start_rng,
ClientLoginStartParameters::WithIdentifiersAndInfo(
Vec::new(),
id_u.to_vec(),
id_s.to_vec(),
),
std::convert::identity,
)
.unwrap();
let l1_bytes = l1.serialize().to_vec();
let client_login_state = client_login.to_bytes().to_vec();
let l1_bytes = client_login_start_result
.credential_request
.serialize()
.to_vec();
let client_login_state = client_login_start_result
.client_login_state
.to_bytes()
.to_vec();
let mut server_e_sk_rng = CycleRng::new(server_e_kp.private().to_arr().to_vec());
let (l2, server_login) = ServerLogin::<CS>::start(
let server_login_start_result = ServerLogin::<CS>::start(
password_file,
server_s_kp.private(),
l1,
client_login_start_result.credential_request,
&mut server_e_sk_rng,
ServerLoginStartParameters::default(),
)
.unwrap();
let l2_bytes = l2.serialize().to_vec();
let server_login_state = server_login.to_bytes().to_vec();
let l2_bytes = server_login_start_result
.credential_response
.serialize()
.to_vec();
let server_login_state = server_login_start_result
.server_login_state
.to_bytes()
.to_vec();
let mut client_e_sk_rng = CycleRng::new(client_e_kp.private().to_arr().to_vec());
let (l3, client_shared_secret, _export_key_login) = client_login
.finish(l2, server_s_kp.public(), &mut client_e_sk_rng)
let client_login_finish_result = client_login_start_result
.client_login_state
.finish(
server_login_start_result.credential_response,
ClientLoginFinishParameters::default(),
)
.unwrap();
let l3_bytes = l3.to_bytes().to_vec();
let l3_bytes = client_login_finish_result.key_exchange.to_bytes().to_vec();
TestVectorParameters {
client_s_pk: client_s_kp.public().to_arr().to_vec(),
@@ -344,7 +364,7 @@ where
server_registration_state,
client_login_state,
server_login_state,
shared_secret: client_shared_secret,
shared_secret: client_login_finish_result.session_secret,
export_key: export_key_registration.to_vec(),
}
}
@@ -365,15 +385,13 @@ fn postprocess_blinding_factor<G: Group>(_: G::Scalar) -> G::Scalar {
fn test_r1() -> Result<(), PakeError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let mut rng = OsRng;
let (r1, client_registration) =
ClientRegistration::<X255193dhNoSlowHash>::start_with_user_and_server_name(
&parameters.id_u,
&parameters.id_s,
&parameters.password,
&mut rng,
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
)
.unwrap();
let (r1, client_registration) = ClientRegistration::<X255193dhNoSlowHash>::start(
&parameters.password,
ClientRegistrationStartParameters::WithIdentifiers(parameters.id_u, parameters.id_s),
&mut rng,
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
)
.unwrap();
assert_eq!(hex::encode(&parameters.r1), hex::encode(r1.serialize()));
assert_eq!(
hex::encode(&parameters.client_registration_state),
@@ -388,6 +406,7 @@ fn test_r2() -> Result<(), PakeError> {
let mut oprf_key_rng = CycleRng::new(parameters.oprf_key);
let (r2, server_registration) = ServerRegistration::<X255193dhNoSlowHash>::start(
RegisterFirstMessage::deserialize(&parameters.r1[..]).unwrap(),
&Key::try_from(&parameters.server_s_pk[..]).unwrap(),
&mut oprf_key_rng,
)
.unwrap();
@@ -412,7 +431,6 @@ fn test_r3() -> Result<(), PakeError> {
.unwrap()
.finish(
RegisterSecondMessage::deserialize(&parameters.r2[..]).unwrap(),
&Key::try_from(&parameters.server_s_pk[..]).unwrap(),
&mut finish_registration_rng,
)
.unwrap();
@@ -456,18 +474,24 @@ fn test_l1() -> Result<(), PakeError> {
]
.concat();
let mut client_login_start_rng = CycleRng::new(client_login_start);
let (l1, client_login) = ClientLogin::<X255193dhNoSlowHash>::start_with_user_and_server_name(
&parameters.id_u,
&parameters.id_s,
let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start(
&parameters.password,
&mut client_login_start_rng,
ClientLoginStartParameters::WithIdentifiersAndInfo(
Vec::new(),
parameters.id_u,
parameters.id_s,
),
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
)
.unwrap();
assert_eq!(hex::encode(&parameters.l1), hex::encode(l1.serialize()));
assert_eq!(
hex::encode(&parameters.l1),
hex::encode(client_login_start_result.credential_request.serialize())
);
assert_eq!(
hex::encode(&parameters.client_login_state),
hex::encode(client_login.to_bytes())
hex::encode(client_login_start_result.client_login_state.to_bytes())
);
Ok(())
}
@@ -477,18 +501,22 @@ 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);
let (l2, server_login) = ServerLogin::<X255193dhNoSlowHash>::start(
let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start(
ServerRegistration::try_from(&parameters.password_file[..]).unwrap(),
&Key::try_from(&parameters.server_s_sk[..]).unwrap(),
LoginFirstMessage::<X255193dhNoSlowHash>::deserialize(&parameters.l1[..]).unwrap(),
&mut server_e_sk_rng,
ServerLoginStartParameters::default(),
)
.unwrap();
assert_eq!(hex::encode(&parameters.l2), hex::encode(l2.serialize()));
assert_eq!(
hex::encode(&parameters.l2),
hex::encode(server_login_start_result.credential_response.serialize())
);
assert_eq!(
hex::encode(&parameters.server_login_state),
hex::encode(server_login.to_bytes())
hex::encode(server_login_start_result.server_login_state.to_bytes())
);
Ok(())
}
@@ -497,25 +525,26 @@ fn test_l2() -> Result<(), PakeError> {
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, export_key_login) =
let client_login_finish_result =
ClientLogin::<X255193dhNoSlowHash>::try_from(&parameters.client_login_state[..])
.unwrap()
.finish(
LoginSecondMessage::<X255193dhNoSlowHash>::deserialize(&parameters.l2[..]).unwrap(),
&Key::try_from(&parameters.server_s_pk[..])?,
&mut client_e_sk_rng,
ClientLoginFinishParameters::default(),
)
.unwrap();
assert_eq!(
hex::encode(&parameters.shared_secret),
hex::encode(&shared_secret)
hex::encode(&client_login_finish_result.session_secret)
);
assert_eq!(
hex::encode(&parameters.l3),
hex::encode(client_login_finish_result.key_exchange.to_bytes())
);
assert_eq!(hex::encode(&parameters.l3), hex::encode(l3.to_bytes()));
assert_eq!(
hex::encode(&parameters.export_key),
hex::encode(export_key_login)
hex::encode(client_login_finish_result.export_key)
);
Ok(())
@@ -525,7 +554,7 @@ fn test_l3() -> Result<(), PakeError> {
fn test_server_login_finish() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let shared_secret =
let server_login_result =
ServerLogin::<X255193dhNoSlowHash>::try_from(&parameters.server_login_state[..])
.unwrap()
.finish(LoginThirdMessage::try_from(&parameters.l3[..])?)
@@ -533,7 +562,7 @@ fn test_server_login_finish() -> Result<(), ProtocolError> {
assert_eq!(
hex::encode(parameters.shared_secret),
hex::encode(shared_secret)
hex::encode(server_login_result.session_secret)
);
Ok(())
@@ -546,36 +575,52 @@ fn test_complete_flow(
let mut client_rng = OsRng;
let mut server_rng = OsRng;
let server_kp = X255193dhNoSlowHash::generate_random_keypair(&mut server_rng)?;
let (register_m1, client_state) =
ClientRegistration::<X255193dhNoSlowHash>::start(registration_password, &mut client_rng)?;
let (register_m2, server_state) =
ServerRegistration::<X255193dhNoSlowHash>::start(register_m1, &mut server_rng)?;
let (register_m3, registration_export_key) =
client_state.finish(register_m2, server_kp.public(), &mut client_rng)?;
let p_file = server_state.finish(register_m3)?;
let (login_m1, client_login_state) =
ClientLogin::<X255193dhNoSlowHash>::start(login_password, &mut client_rng)?;
let (login_m2, server_login_state) = ServerLogin::<X255193dhNoSlowHash>::start(
p_file,
&server_kp.private(),
login_m1,
let (register_m1, client_state) = ClientRegistration::<X255193dhNoSlowHash>::start(
registration_password,
ClientRegistrationStartParameters::default(),
&mut client_rng,
std::convert::identity,
)?;
let (register_m2, server_state) = ServerRegistration::<X255193dhNoSlowHash>::start(
register_m1,
server_kp.public(),
&mut server_rng,
)?;
let (register_m3, registration_export_key) =
client_state.finish(register_m2, &mut client_rng)?;
let p_file = server_state.finish(register_m3)?;
let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start(
login_password,
&mut client_rng,
ClientLoginStartParameters::default(),
std::convert::identity,
)?;
let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start(
p_file,
&server_kp.private(),
client_login_start_result.credential_request,
&mut server_rng,
ServerLoginStartParameters::default(),
)?;
let client_login_result =
client_login_state.finish(login_m2, &server_kp.public(), &mut client_rng);
let client_login_result = client_login_start_result.client_login_state.finish(
server_login_start_result.credential_response,
ClientLoginFinishParameters::default(),
);
if hex::encode(registration_password) == hex::encode(login_password) {
let (login_m3, client_shared_secret, login_export_key) = client_login_result?;
let server_shared_secret = server_login_state.finish(login_m3)?;
let client_login_finish_result = client_login_result?;
let server_login_finish_result = server_login_start_result
.server_login_state
.finish(client_login_finish_result.key_exchange)?;
assert_eq!(
hex::encode(server_shared_secret),
hex::encode(client_shared_secret)
hex::encode(server_login_finish_result.session_secret),
hex::encode(client_login_finish_result.session_secret)
);
assert_eq!(
hex::encode(registration_export_key),
hex::encode(login_export_key)
hex::encode(client_login_finish_result.export_key)
);
} else {
let res = matches!(