Adding API for handling info fields (#88)
This commit is contained in:
+29
-22
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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(®istration_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(®istration_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(®istration_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
File diff suppressed because it is too large
Load Diff
@@ -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 {
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
keypair::{KeyPair, X25519KeyPair},
|
||||
opaque::*,
|
||||
serialization::{i2osp, os2ip, serialize, ProtocolMessageType},
|
||||
*,
|
||||
};
|
||||
|
||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
|
||||
+112
-67
@@ -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(
|
||||
¶meters.id_u,
|
||||
¶meters.id_s,
|
||||
¶meters.password,
|
||||
&mut rng,
|
||||
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
|
||||
)
|
||||
.unwrap();
|
||||
let (r1, client_registration) = ClientRegistration::<X255193dhNoSlowHash>::start(
|
||||
¶meters.password,
|
||||
ClientRegistrationStartParameters::WithIdentifiers(parameters.id_u, parameters.id_s),
|
||||
&mut rng,
|
||||
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(hex::encode(¶meters.r1), hex::encode(r1.serialize()));
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.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(¶meters.r1[..]).unwrap(),
|
||||
&Key::try_from(¶meters.server_s_pk[..]).unwrap(),
|
||||
&mut oprf_key_rng,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -412,7 +431,6 @@ fn test_r3() -> Result<(), PakeError> {
|
||||
.unwrap()
|
||||
.finish(
|
||||
RegisterSecondMessage::deserialize(¶meters.r2[..]).unwrap(),
|
||||
&Key::try_from(¶meters.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(
|
||||
¶meters.id_u,
|
||||
¶meters.id_s,
|
||||
let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start(
|
||||
¶meters.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(¶meters.l1), hex::encode(l1.serialize()));
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.l1),
|
||||
hex::encode(client_login_start_result.credential_request.serialize())
|
||||
);
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.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(¶meters.password_file[..]).unwrap(),
|
||||
&Key::try_from(¶meters.server_s_sk[..]).unwrap(),
|
||||
LoginFirstMessage::<X255193dhNoSlowHash>::deserialize(¶meters.l1[..]).unwrap(),
|
||||
&mut server_e_sk_rng,
|
||||
ServerLoginStartParameters::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(hex::encode(¶meters.l2), hex::encode(l2.serialize()));
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.l2),
|
||||
hex::encode(server_login_start_result.credential_response.serialize())
|
||||
);
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.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(¶meters.client_login_state[..])
|
||||
.unwrap()
|
||||
.finish(
|
||||
LoginSecondMessage::<X255193dhNoSlowHash>::deserialize(¶meters.l2[..]).unwrap(),
|
||||
&Key::try_from(¶meters.server_s_pk[..])?,
|
||||
&mut client_e_sk_rng,
|
||||
ClientLoginFinishParameters::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.shared_secret),
|
||||
hex::encode(&shared_secret)
|
||||
hex::encode(&client_login_finish_result.session_secret)
|
||||
);
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.l3),
|
||||
hex::encode(client_login_finish_result.key_exchange.to_bytes())
|
||||
);
|
||||
assert_eq!(hex::encode(¶meters.l3), hex::encode(l3.to_bytes()));
|
||||
assert_eq!(
|
||||
hex::encode(¶meters.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(¶meters.server_login_state[..])
|
||||
.unwrap()
|
||||
.finish(LoginThirdMessage::try_from(¶meters.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!(
|
||||
|
||||
Reference in New Issue
Block a user