Cleaning up docs + README (#98)

This commit is contained in:
Kevin Lewi
2020-12-12 21:53:33 -08:00
committed by GitHub
parent 9e3743a604
commit 605d2b639b
7 changed files with 498 additions and 396 deletions
+3 -2
View File
@@ -29,7 +29,8 @@ Resources
--------- ---------
- [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of security - [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of security
- [draft-krawczyk-cfrg-opaque-05](https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-06), containing a specification for the OPAQUE protocol - [draft-irtf-cfrg-opaque-01](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-01.html), containing a detailed (byte-level) specification for OPAQUE
- [draft-krawczyk-cfrg-opaque-06](https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-06), containing a high-level specification for OPAQUE
- ["Let's talk about PAKE"](https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/), an introductory blog post written by Matthew Green that covers OPAQUE - ["Let's talk about PAKE"](https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/), an introductory blog post written by Matthew Green that covers OPAQUE
Contributors Contributors
@@ -41,7 +42,7 @@ To learn more about contributing to this project, [see this document](./CONTRIBU
#### Acknowledgments #### Acknowledgments
Special thanks go to Hugo Krawczyk for helping to clarify discrepancies and making suggestions for improving Special thanks go to Hugo Krawczyk and Chris Wood for helping to clarify discrepancies and making suggestions for improving
this implementation. this implementation.
+33 -31
View File
@@ -30,8 +30,8 @@ use std::process::exit;
use opaque_ke::{ use opaque_ke::{
ciphersuite::CipherSuite, keypair::KeyPair, ClientLogin, ClientLoginFinishParameters, ciphersuite::CipherSuite, keypair::KeyPair, ClientLogin, ClientLoginFinishParameters,
ClientLoginStartParameters, ClientRegistration, ClientRegistrationStartParameters, ClientLoginStartParameters, ClientRegistration, ClientRegistrationStartParameters,
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage, CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegisterSecondMessage, RegisterThirdMessage, ServerLogin, ServerLoginStartParameters, RegistrationResponse, RegistrationUpload, ServerLogin, ServerLoginStartParameters,
ServerRegistration, ServerRegistration,
}; };
@@ -53,39 +53,41 @@ fn account_registration(
password: String, password: String,
) -> Vec<u8> { ) -> Vec<u8> {
let mut client_rng = OsRng; let mut client_rng = OsRng;
let (r1, client_state) = ClientRegistration::<Default>::start( let client_registration_start_result = ClientRegistration::<Default>::start(
&mut client_rng,
password.as_bytes(), password.as_bytes(),
ClientRegistrationStartParameters::default(), ClientRegistrationStartParameters::default(),
&mut client_rng,
) )
.unwrap(); .unwrap();
let r1_bytes = r1.serialize(); let registration_request_bytes = client_registration_start_result.message.serialize();
// Client sends r1_bytes to server // Client sends registration_request_bytes to server
let mut server_rng = OsRng; let mut server_rng = OsRng;
let (r2, server_state) = ServerRegistration::<Default>::start( let server_registration_start_result = ServerRegistration::<Default>::start(
RegisterFirstMessage::deserialize(&r1_bytes[..]).unwrap(),
server_kp.public(),
&mut server_rng, &mut server_rng,
RegistrationRequest::deserialize(&registration_request_bytes[..]).unwrap(),
server_kp.public(),
) )
.unwrap(); .unwrap();
let r2_bytes = r2.serialize(); let registration_response_bytes = server_registration_start_result.message.serialize();
// Server sends r2_bytes to client // Server sends registration_response_bytes to client
let (r3, _) = client_state let client_finish_registration_result = client_registration_start_result
.state
.finish( .finish(
RegisterSecondMessage::deserialize(&r2_bytes[..]).unwrap(),
&mut client_rng, &mut client_rng,
RegistrationResponse::deserialize(&registration_response_bytes[..]).unwrap(),
) )
.unwrap(); .unwrap();
let r3_bytes = r3.serialize(); let message_bytes = client_finish_registration_result.message.serialize();
// Client sends r3_bytes to server // Client sends message_bytes to server
let password_file = server_state let password_file = server_registration_start_result
.finish(RegisterThirdMessage::deserialize(&r3_bytes[..]).unwrap()) .state
.finish(RegistrationUpload::deserialize(&message_bytes[..]).unwrap())
.unwrap(); .unwrap();
password_file.to_bytes() password_file.to_bytes()
} }
@@ -98,31 +100,31 @@ fn account_login(
) -> bool { ) -> bool {
let mut client_rng = OsRng; let mut client_rng = OsRng;
let client_login_start_result = ClientLogin::<Default>::start( let client_login_start_result = ClientLogin::<Default>::start(
password.as_bytes(),
&mut client_rng, &mut client_rng,
password.as_bytes(),
ClientLoginStartParameters::default(), ClientLoginStartParameters::default(),
) )
.unwrap(); .unwrap();
let l1_bytes = client_login_start_result.credential_request.serialize(); let credential_request_bytes = client_login_start_result.message.serialize();
// Client sends l1_bytes to server // Client sends credential_request_bytes to server
let password_file = ServerRegistration::<Default>::try_from(password_file_bytes).unwrap(); let password_file = ServerRegistration::<Default>::try_from(password_file_bytes).unwrap();
let mut server_rng = OsRng; let mut server_rng = OsRng;
let server_login_start_result = ServerLogin::start( let server_login_start_result = ServerLogin::start(
&mut server_rng,
password_file, password_file,
&server_kp.private(), &server_kp.private(),
LoginFirstMessage::deserialize(&l1_bytes[..]).unwrap(), CredentialRequest::deserialize(&credential_request_bytes[..]).unwrap(),
&mut server_rng,
ServerLoginStartParameters::default(), ServerLoginStartParameters::default(),
) )
.unwrap(); .unwrap();
let l2_bytes = server_login_start_result.credential_response.serialize(); let credential_response_bytes = server_login_start_result.message.serialize();
// Server sends l2_bytes to client // Server sends credential_response_bytes to client
let result = client_login_start_result.client_login_state.finish( let result = client_login_start_result.state.finish(
LoginSecondMessage::deserialize(&l2_bytes[..]).unwrap(), CredentialResponse::deserialize(&credential_response_bytes[..]).unwrap(),
ClientLoginFinishParameters::default(), ClientLoginFinishParameters::default(),
); );
@@ -131,16 +133,16 @@ fn account_login(
return false; return false;
} }
let client_login_finish_result = result.unwrap(); let client_login_finish_result = result.unwrap();
let l3_bytes = client_login_finish_result.key_exchange.serialize(); let credential_finalization_bytes = client_login_finish_result.message.serialize();
// Client sends l3_bytes to server // Client sends credential_finalization_bytes to server
let server_login_finish_result = server_login_start_result let server_login_finish_result = server_login_start_result
.server_login_state .state
.finish(LoginThirdMessage::deserialize(&l3_bytes[..]).unwrap()) .finish(CredentialFinalization::deserialize(&credential_finalization_bytes[..]).unwrap())
.unwrap(); .unwrap();
client_login_finish_result.session_secret == server_login_finish_result.session_secret client_login_finish_result.shared_secret == server_login_finish_result.shared_secret
} }
// A function run on the client which extracts a username and password from the CLI // A function run on the client which extracts a username and password from the CLI
+131 -108
View File
@@ -5,7 +5,7 @@
//! An implementation of the OPAQUE asymmetric password authentication key exchange protocol //! An implementation of the OPAQUE asymmetric password authentication key exchange protocol
//! //!
//! Note: This implementation is in sync with [draft-krawczyk-cfrg-opaque-06](https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-06), //! Note: This implementation is in sync with [draft-irtf-cfrg-opaque-01](https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-01.html),
//! but this specification is subject to change, until the final version published by the IETF. //! but this specification is subject to change, until the final version published by the IETF.
//! //!
//! # Overview //! # Overview
@@ -32,13 +32,11 @@
//! ``` //! ```
//! //!
//! Note that our choice of slow hashing function in this example, `NoOpHash`, is selected only to ensure //! Note that our choice of slow hashing function in this example, `NoOpHash`, is selected only to ensure
//! that the tests execute quickly. A real application should use an actual slow hashing function, such as `Scrypt`. //! that the tests execute quickly. A real application should use an actual slow hashing function, such as `scrypt`,
//! //! which can be enabled through the `slow-hash` feature.
//! We have included a concrete instantiation of the authenticated key exchange protocol using 3DH. In the future, we plan to
//! add support for other KE protocols as well.
//! //!
//! ## Setup //! ## Setup
//! To setup the protocol, the server begins by generating a static keypair: //! To set up the protocol, the server begins by generating a static keypair:
//! ``` //! ```
//! # use opaque_ke::keypair::{KeyPair, X25519KeyPair}; //! # use opaque_ke::keypair::{KeyPair, X25519KeyPair};
//! # use opaque_ke::errors::ProtocolError; //! # use opaque_ke::errors::ProtocolError;
@@ -60,14 +58,15 @@
//! used by the client during both registration and login, and the private component will be used by the server during login. //! used by the client during both registration and login, and the private component will be used by the server during login.
//! //!
//! ## Registration //! ## Registration
//! The registration protocol between the client and server consists of four steps along with three messages, denoted //! The registration protocol between the client and server consists of four steps along with three messages:
//! as `r1`, `r2`, and `r3`. Before registration begins, it is expected that the server's static public key, `server_kp.public()`, //! [RegistrationRequest], [RegistrationResponse], and [RegistrationUpload]. A successful execution of the registration protocol results in the
//! has been transmitted to the client in an offline step. A successful execution of the registration protocol results in the //! server producing a password file corresponding to the password provided by
//! server producing a password file corresponding to the tuple combination of (password, pepper, server public key) provided by
//! the client. This password file is typically stored server-side, and retrieved upon future login attempts made by the client. //! the client. This password file is typically stored server-side, and retrieved upon future login attempts made by the client.
//! //!
//! In the first step (client registration start), the client chooses a registration password and an optional "pepper", and //! ### Client Registration Start
//! runs `ClientRegistration::start` to produce a message `r1`: //! In the first step of registration, the client chooses as input a registration password. The client runs [ClientRegistration::start]
//! to produce an output consisting of a [RegistrationRequest] to be sent to the server, and
//! a [ClientRegistration] which must be persisted on the client for the final step of client registration.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
@@ -87,18 +86,20 @@
//! use opaque_ke::{ClientRegistration, ClientRegistrationStartParameters}; //! use opaque_ke::{ClientRegistration, ClientRegistrationStartParameters};
//! use rand_core::{OsRng, RngCore}; //! use rand_core::{OsRng, RngCore};
//! let mut client_rng = OsRng; //! let mut client_rng = OsRng;
//! let (r1, client_state) = ClientRegistration::<Default>::start( //! let client_registration_start_result = ClientRegistration::<Default>::start(
//! &mut client_rng,
//! b"password", //! b"password",
//! ClientRegistrationStartParameters::default(), //! ClientRegistrationStartParameters::default(),
//! &mut client_rng,
//! )?; //! )?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! `r1` is sent to the server, and `client_state` must be persisted on the client for the final step of client
//! registration.
//! //!
//! In the second step (server registration start), the server takes as input the `r1` message from the client and runs //! ### Server Registration Start
//! `ServerRegistration::start` to produce `r2`: //! In the second step of registration, the server takes as input the instance of [RegistrationRequest] from the client, and
//! the server's public key `server_kp.public()`.
//! The server runs [ServerRegistration::start] to produce an output consisting of
//! a [RegistrationResponse] to be returned to the client, and
//! a [ServerRegistration] which must be persisted on the server for the final step of server registration.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
@@ -117,23 +118,28 @@
//! # } //! # }
//! # use rand_core::{OsRng, RngCore}; //! # use rand_core::{OsRng, RngCore};
//! # let mut client_rng = OsRng; //! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password", //! # b"password",
//! # ClientRegistrationStartParameters::default(), //! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?; //! # )?;
//! use opaque_ke::ServerRegistration; //! use opaque_ke::ServerRegistration;
//! let mut server_rng = OsRng; //! let mut server_rng = OsRng;
//! let server_kp = Default::generate_random_keypair(&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 server_registration_start_result = ServerRegistration::<Default>::start(
//! &mut server_rng,
//! client_registration_start_result.message,
//! server_kp.public(),
//! )?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! `r2` is returned to the client, and `server_state` must be persisted on the server for the final step of server
//! registration.
//! //!
//! In the third step (client registration finish), the client takes as input the `r2` message from the server, along //! ### Client Registration Finish
//! with the server's static public key `server_kp.public()`, and uses `client_state` from the first step to run //! In the third step of registration, the client takes as input
//! `finish` and produce a message `r3` along with the export key `export_key_registration`: //! a [RegistrationResponse] from the server, and
//! a [ClientRegistration] from the first step of registration.
//! The client runs [ClientRegistration::finish] to produce an output consisting of a [RegistrationUpload]
//! to be sent to the server.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
@@ -152,23 +158,28 @@
//! # } //! # }
//! # use rand_core::{OsRng, RngCore}; //! # use rand_core::{OsRng, RngCore};
//! # let mut client_rng = OsRng; //! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password", //! # b"password",
//! # ClientRegistrationStartParameters::default(), //! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&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 server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! let (r3, export_key_registration) = //! let client_registration_finish_result = client_registration_start_result.state.finish(
//! client_state.finish(r2, &mut client_rng)?; //! &mut client_rng,
//! server_registration_start_result.message,
//! )?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! `r3` is sent to the server, and the client can optionally use `export_key_registration` for applications that choose to
//! process user information beyond the OPAQUE functionality (e.g., additional secrets or credentials).
//! //!
//! In the fourth step of registration, the server takes as input the `r3` message from the client and uses //! ### Server Registration Finish
//! `server_state` from the second step to run `finish` and produce `password_file`: //! In the fourth step of registration, the server takes as input
//! a [RegistrationUpload] from the client, and
//! a [ServerRegistration] from the second step.
//! The server runs [ServerRegistration::finish] to produce a finalized [ServerRegistration].
//! At this point, the client can be considered as successfully registered, and the server can invoke
//! [ServerRegistration::to_bytes] to store the password file for use during the login protocol.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
@@ -187,35 +198,36 @@
//! # } //! # }
//! # use rand_core::{OsRng, RngCore}; //! # use rand_core::{OsRng, RngCore};
//! # let mut client_rng = OsRng; //! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password", //! # b"password",
//! # ClientRegistrationStartParameters::default(), //! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&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 server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! let password_file = server_state.finish(r3)?; //! let password_file = server_registration_start_result.state.finish(
//! client_registration_finish_result.message,
//! )?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! At this point, the client can be considered as successfully registered, and the server can store
//! `password_file.to_bytes()` for use during the login protocol.
//!
//! //!
//! ## Login //! ## Login
//! The login protocol between a client and server also consists of four steps along with three messages, denoted as //! The login protocol between a client and server also consists of four steps along with three messages:
//! `l1`, `l2`, and `l3`. The server is expected to have access to the a password file corresponding to an output //! [CredentialRequest], [CredentialResponse], [CredentialFinalization]. The server is expected to have access to the password file
//! of the registration phase. The login protocol will execute successfully only if the same tuple combination of //! corresponding to an output of the registration phase. The login protocol will execute successfully only if the same password
//! (password, pepper, server public key) is presented as was used in the registration phase that produced the //! was used in the registration phase that produced the password file that the server is testing against.
//! password file that the server is testing against.
//! //!
//! In the first step (client login start), the client chooses a registration password and an optional "pepper", and runs //! ### Client Login Start
//! `ClientLogin::start` to produce a message `l1`: //! In the first step of login, the client chooses as input a login password.
//! The client runs [ClientLogin::start] to produce an output consisting of
//! a [CredentialRequest] to be sent to the server, and
//! a [ClientLogin] which must be persisted on the client for the final step of client login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ServerRegistration, ServerLogin, LoginThirdMessage, //! # ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair}, //! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash, //! # slow_hash::NoOpHash,
//! # }; //! # };
@@ -232,22 +244,25 @@
//! use opaque_ke::{ClientLogin, ClientLoginStartParameters}; //! use opaque_ke::{ClientLogin, ClientLoginStartParameters};
//! let mut client_rng = OsRng; //! let mut client_rng = OsRng;
//! let client_login_start_result = ClientLogin::<Default>::start( //! let client_login_start_result = ClientLogin::<Default>::start(
//! b"password",
//! &mut client_rng, //! &mut client_rng,
//! b"password",
//! ClientLoginStartParameters::default(), //! ClientLoginStartParameters::default(),
//! )?; //! )?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! `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 //! ### Server Login Start
//! private key `server_kp.private()`, along with a serialized version of the password file, `password_file_bytes`, and //! In the second step of login, the server takes as input
//! runs `ServerLogin::start` to produce `server_login_start_result`: //! a [CredentialRequest] from the client,
//! the server's private key `server_kp.private()`, and
//! the password file output from registration.
//! The server runs [ServerLogin::start] to produce an output consisting of
//! a [CredentialResponse] which is returned to the client, and
//! a [ServerLogin] which must be persisted on the server for the final step of login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, LoginThirdMessage, //! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair}, //! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash, //! # slow_hash::NoOpHash,
//! # }; //! # };
@@ -262,39 +277,44 @@
//! # } //! # }
//! # use rand_core::{OsRng, RngCore}; //! # use rand_core::{OsRng, RngCore};
//! # let mut client_rng = OsRng; //! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password", //! # b"password",
//! # ClientRegistrationStartParameters::default(), //! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&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 server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes(); //! # let password_file_bytes = server_registration_start_result.state.finish(client_registration_finish_result.message)?.to_bytes();
//! # let client_login_start_result = ClientLogin::<Default>::start( //! # let client_login_start_result = ClientLogin::<Default>::start(
//! # b"password",
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password",
//! # ClientLoginStartParameters::default(), //! # ClientLoginStartParameters::default(),
//! # )?; //! # )?;
//! use opaque_ke::{ServerLogin, ServerLoginStartParameters}; //! use opaque_ke::{ServerLogin, ServerLoginStartParameters};
//! use std::convert::TryFrom; //! use std::convert::TryFrom;
//! let password_file = ServerRegistration::<Default>::try_from(&password_file_bytes[..])?; //! let password_file = ServerRegistration::<Default>::try_from(&password_file_bytes[..])?;
//! let mut server_rng = OsRng; //! let mut server_rng = OsRng;
//! let server_login_start_result = //! let server_login_start_result = ServerLogin::start(
//! ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?; //! &mut server_rng,
//! password_file,
//! &server_kp.private(),
//! client_login_start_result.message,
//! ServerLoginStartParameters::default(),
//! )?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! `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 //! ### Client Login Finish
//! server's static public key `server_kp.public()`, and uses `client_state` from the first step to run `finish` and produce //! In the third step of login, the client takes as input a [CredentialResponse] from the server.
//! a message `l3`, the shared secret `client_shared_secret`, and the export key `export_key_login`: //! The client runs [ClientLogin::finish] and produces an output consisting of
//! a [CredentialFinalization] to be sent to the server to complete the protocol,
//! the `shared_secret` sequence of bytes which will match the server's shared secret upon a successful login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage, //! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair}, //! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash, //! # slow_hash::NoOpHash,
//! # }; //! # };
@@ -309,20 +329,20 @@
//! # } //! # }
//! # use rand_core::{OsRng, RngCore}; //! # use rand_core::{OsRng, RngCore};
//! # let mut client_rng = OsRng; //! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password", //! # b"password",
//! # ClientRegistrationStartParameters::default(), //! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&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 server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes(); //! # let password_file_bytes = server_registration_start_result.state.finish(client_registration_finish_result.message)?.to_bytes();
//! # let client_login_start_result = ClientLogin::<Default>::start( //! # let client_login_start_result = ClientLogin::<Default>::start(
//! # b"password", //! # &mut client_rng,
//! # &mut client_rng, //! # b"password",
//! # ClientLoginStartParameters::default(), //! # ClientLoginStartParameters::default(),
//! # )?; //! # )?;
//! # use std::convert::TryFrom; //! # use std::convert::TryFrom;
//! # let password_file = //! # let password_file =
@@ -330,27 +350,25 @@
//! # &password_file_bytes[..], //! # &password_file_bytes[..],
//! # )?; //! # )?;
//! # let server_login_start_result = //! # let server_login_start_result =
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?; //! # ServerLogin::start(&mut server_rng, password_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default())?;
//! let client_login_finish_result = client_login_start_result.client_login_state.finish( //! let client_login_finish_result = client_login_start_result.state.finish(
//! server_login_start_result.credential_response, //! server_login_start_result.message,
//! ClientLoginFinishParameters::default(), //! ClientLoginFinishParameters::default(),
//! )?; //! )?;
//! assert_eq!(export_key_registration, client_login_finish_result.export_key); //! assert_eq!(
//! client_registration_finish_result.export_key,
//! client_login_finish_result.export_key,
//! );
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! Note that if the client supplies a tuple (password, pepper, server public key) that does not match the tuple
//! used to create the password file, then at this point the `finish` algorithm outputs the error `InvalidLoginError`.
//! //!
//! If `finish` completes successfully, then `l3` is sent to the server, and (similarly to registration) the client //! ### Server Login Finish
//! can use `export_key_login` for applications that can take advantage of the fact that this key is identical to //! In the fourth step of login, the server takes as input a [CredentialFinalization] from the client and runs [ServerLogin::finish] to
//! `export_key_registration`. //! produce an output consisting of the `shared_secret` sequence of bytes which will match the client's shared secret upon a successful login.
//!
//! In the fourth step of login, the server takes as input the `l3` message from the client and uses `server_state` from
//! the second step to run `finish`:
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_ke::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage, //! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair}, //! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash, //! # slow_hash::NoOpHash,
//! # }; //! # };
@@ -365,19 +383,19 @@
//! # } //! # }
//! # use rand_core::{OsRng, RngCore}; //! # use rand_core::{OsRng, RngCore};
//! # let mut client_rng = OsRng; //! # let mut client_rng = OsRng;
//! # let (r1, client_state) = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password", //! # b"password",
//! # ClientRegistrationStartParameters::default(), //! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&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 server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let (r3, export_key) = client_state.finish(r2, &mut client_rng)?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes(); //! # let password_file_bytes = server_registration_start_result.state.finish(client_registration_finish_result.message)?.to_bytes();
//! # let client_login_start_result = ClientLogin::<Default>::start( //! # let client_login_start_result = ClientLogin::<Default>::start(
//! # b"password",
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password",
//! # ClientLoginStartParameters::default(), //! # ClientLoginStartParameters::default(),
//! # )?; //! # )?;
//! # use std::convert::TryFrom; //! # use std::convert::TryFrom;
@@ -386,17 +404,22 @@
//! # &password_file_bytes[..], //! # &password_file_bytes[..],
//! # )?; //! # )?;
//! # let server_login_start_result = //! # let server_login_start_result =
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?; //! # ServerLogin::start(&mut server_rng, password_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default())?;
//! # let client_login_finish_result = client_login_start_result.client_login_state.finish( //! # let client_login_finish_result = client_login_start_result.state.finish(
//! # server_login_start_result.credential_response, //! # server_login_start_result.message,
//! # ClientLoginFinishParameters::default(), //! # ClientLoginFinishParameters::default(),
//! # )?; //! # )?;
//! let server_login_finish_result = server_login_start_result.server_login_state.finish(client_login_finish_result.key_exchange)?; //! let server_login_finish_result = server_login_start_result.state.finish(
//! assert_eq!(client_login_finish_result.session_secret, server_login_finish_result.session_secret); //! client_login_finish_result.message,
//! )?;
//! assert_eq!(
//! client_login_finish_result.shared_secret,
//! server_login_finish_result.shared_secret,
//! );
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
//! If the protocol completes successfully, then the server obtains a `server_shared_secret` which is guaranteed to //! If the protocol completes successfully, then the server obtains a `server_login_finish_result.shared_secret` which is guaranteed to
//! match `client_shared_secret`. Otherwise, on failure, the `finish` algorithm outputs the error `InvalidLoginError`. //! match `client_login_finish_result.shared_secret`. Otherwise, on failure, the [ServerLogin::finish] algorithm outputs the error [InvalidLoginError](errors::PakeError::InvalidLoginError).
//! //!
#![cfg_attr(not(feature = "bench"), deny(missing_docs))] #![cfg_attr(not(feature = "bench"), deny(missing_docs))]
@@ -443,8 +466,8 @@ mod tests;
// Exports // Exports
pub use crate::messages::{ pub use crate::messages::{
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage, CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegisterSecondMessage, RegisterThirdMessage, RegistrationResponse, RegistrationUpload,
}; };
pub use crate::opaque::{ClientLogin, ClientRegistration, ServerLogin, ServerRegistration}; pub use crate::opaque::{ClientLogin, ClientRegistration, ServerLogin, ServerRegistration};
pub use crate::opaque::{ pub use crate::opaque::{
+23 -23
View File
@@ -26,12 +26,12 @@ use std::convert::TryFrom;
// ========= // =========
/// The message sent by the client to the server, to initiate registration /// The message sent by the client to the server, to initiate registration
pub struct RegisterFirstMessage<Grp> { pub struct RegistrationRequest<Grp> {
/// blinded password information /// blinded password information
pub(crate) alpha: Grp, pub(crate) alpha: Grp,
} }
impl<Grp: Group> TryFrom<&[u8]> for RegisterFirstMessage<Grp> { impl<Grp: Group> TryFrom<&[u8]> for RegistrationRequest<Grp> {
type Error = ProtocolError; type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> { fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let elem_len = Grp::ElemLen::to_usize(); let elem_len = Grp::ElemLen::to_usize();
@@ -45,7 +45,7 @@ impl<Grp: Group> TryFrom<&[u8]> for RegisterFirstMessage<Grp> {
} }
} }
impl<Grp: Group> RegisterFirstMessage<Grp> { impl<Grp: Group> RegistrationRequest<Grp> {
/// Byte representation for the registration request /// Byte representation for the registration request
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
self.alpha.to_arr().to_vec() self.alpha.to_arr().to_vec()
@@ -79,7 +79,7 @@ impl<Grp: Group> RegisterFirstMessage<Grp> {
/// The answer sent by the server to the user, upon reception of the /// The answer sent by the server to the user, upon reception of the
/// registration attempt /// registration attempt
pub struct RegisterSecondMessage<Grp> { pub struct RegistrationResponse<Grp> {
/// The server's oprf output /// The server's oprf output
pub(crate) beta: Grp, pub(crate) beta: Grp,
/// Server's static public key /// Server's static public key
@@ -88,7 +88,7 @@ pub struct RegisterSecondMessage<Grp> {
pub(crate) ecf: EnvelopeCredentialsFormat, pub(crate) ecf: EnvelopeCredentialsFormat,
} }
impl<Grp> TryFrom<&[u8]> for RegisterSecondMessage<Grp> impl<Grp> TryFrom<&[u8]> for RegistrationResponse<Grp>
where where
Grp: Group, Grp: Group,
{ {
@@ -116,7 +116,7 @@ where
} }
} }
impl<Grp> RegisterSecondMessage<Grp> impl<Grp> RegistrationResponse<Grp>
where where
Grp: Group, Grp: Group,
{ {
@@ -196,7 +196,7 @@ where
/// The final message from the client, containing sealed cryptographic /// The final message from the client, containing sealed cryptographic
/// identifiers /// identifiers
pub struct RegisterThirdMessage<KeyFormat: KeyPair, D: Hash> { pub struct RegistrationUpload<KeyFormat: KeyPair, D: Hash> {
/// The "envelope" generated by the user, containing sealed /// The "envelope" generated by the user, containing sealed
/// cryptographic identifiers /// cryptographic identifiers
pub(crate) envelope: Envelope<D>, pub(crate) envelope: Envelope<D>,
@@ -204,7 +204,7 @@ pub struct RegisterThirdMessage<KeyFormat: KeyPair, D: Hash> {
pub(crate) client_s_pk: KeyFormat::Repr, pub(crate) client_s_pk: KeyFormat::Repr,
} }
impl<KeyFormat, D> TryFrom<&[u8]> for RegisterThirdMessage<KeyFormat, D> impl<KeyFormat, D> TryFrom<&[u8]> for RegistrationUpload<KeyFormat, D>
where where
KeyFormat: KeyPair, KeyFormat: KeyPair,
D: Hash, D: Hash,
@@ -229,17 +229,17 @@ where
} }
} }
impl<KeyFormat, D> RegisterThirdMessage<KeyFormat, D> impl<KeyFormat, D> RegistrationUpload<KeyFormat, D>
where where
KeyFormat: KeyPair, KeyFormat: KeyPair,
D: Hash, D: Hash,
{ {
/// Serialization into bytes /// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let mut registration_upload: Vec<u8> = Vec::new(); let mut message: Vec<u8> = Vec::new();
registration_upload.extend_from_slice(&self.envelope.serialize()); message.extend_from_slice(&self.envelope.serialize());
registration_upload.extend_from_slice(&serialize(&self.client_s_pk.to_arr(), 2)); message.extend_from_slice(&serialize(&self.client_s_pk.to_arr(), 2));
registration_upload message
} }
/// Deserialization from bytes /// Deserialization from bytes
@@ -259,20 +259,20 @@ where
} }
/// The message sent by the user to the server, to initiate registration /// The message sent by the user to the server, to initiate registration
pub struct LoginFirstMessage<CS: CipherSuite> { pub struct CredentialRequest<CS: CipherSuite> {
/// blinded password information /// blinded password information
pub(crate) alpha: CS::Group, pub(crate) alpha: CS::Group,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE1Message, pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE1Message,
} }
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> { impl<CS: CipherSuite> TryFrom<&[u8]> for CredentialRequest<CS> {
type Error = ProtocolError; type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> { fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
Self::deserialize(first_message_bytes) Self::deserialize(first_message_bytes)
} }
} }
impl<CS: CipherSuite> LoginFirstMessage<CS> { impl<CS: CipherSuite> CredentialRequest<CS> {
/// byte representation for the login request /// byte representation for the login request
pub(crate) fn to_bytes(&self) -> Vec<u8> { pub(crate) fn to_bytes(&self) -> Vec<u8> {
[&self.alpha.to_arr()[..], &self.ke1_message.to_bytes()].concat() [&self.alpha.to_arr()[..], &self.ke1_message.to_bytes()].concat()
@@ -305,8 +305,8 @@ impl<CS: CipherSuite> LoginFirstMessage<CS> {
} }
/// The answer sent by the server to the user, upon reception of the /// The answer sent by the server to the user, upon reception of the
/// login attempt. /// login attempt
pub struct LoginSecondMessage<CS: CipherSuite> { pub struct CredentialResponse<CS: CipherSuite> {
/// the server's oprf output /// the server's oprf output
pub(crate) beta: CS::Group, pub(crate) beta: CS::Group,
/// the user's sealed information, /// the user's sealed information,
@@ -314,7 +314,7 @@ pub struct LoginSecondMessage<CS: CipherSuite> {
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE2Message, pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE2Message,
} }
impl<CS: CipherSuite> LoginSecondMessage<CS> { impl<CS: CipherSuite> CredentialResponse<CS> {
/// Serialization into bytes /// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let mut credential_response: Vec<u8> = Vec::new(); let mut credential_response: Vec<u8> = Vec::new();
@@ -332,7 +332,7 @@ impl<CS: CipherSuite> LoginSecondMessage<CS> {
} }
} }
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginSecondMessage<CS> { impl<CS: CipherSuite> TryFrom<&[u8]> for CredentialResponse<CS> {
type Error = ProtocolError; type Error = ProtocolError;
fn try_from(second_message_bytes: &[u8]) -> Result<Self, Self::Error> { fn try_from(second_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize(); let elem_len = <CS::Group as Group>::ElemLen::to_usize();
@@ -365,11 +365,11 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for LoginSecondMessage<CS> {
/// The answer sent by the client to the server, upon reception of the /// The answer sent by the client to the server, upon reception of the
/// sealed envelope /// sealed envelope
pub struct LoginThirdMessage<CS: CipherSuite> { pub struct CredentialFinalization<CS: CipherSuite> {
pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE3Message, pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE3Message,
} }
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginThirdMessage<CS> { impl<CS: CipherSuite> TryFrom<&[u8]> for CredentialFinalization<CS> {
type Error = ProtocolError; type Error = ProtocolError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
@@ -379,7 +379,7 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for LoginThirdMessage<CS> {
} }
} }
impl<CS: CipherSuite> LoginThirdMessage<CS> { impl<CS: CipherSuite> CredentialFinalization<CS> {
/// Serialization into bytes /// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
self.ke3_message.to_bytes() self.ke3_message.to_bytes()
+113 -92
View File
@@ -17,8 +17,8 @@ use crate::{
oprf, oprf,
serialization::{serialize, tokenize, CredentialType}, serialization::{serialize, tokenize, CredentialType},
slow_hash::SlowHash, slow_hash::SlowHash,
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage, CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegisterSecondMessage, RegisterThirdMessage, RegistrationResponse, RegistrationUpload,
}; };
use generic_array::{typenum::Unsigned, GenericArray}; use generic_array::{typenum::Unsigned, GenericArray};
use generic_bytes::SizedBytes; use generic_bytes::SizedBytes;
@@ -102,6 +102,14 @@ impl Default for ClientRegistrationStartParameters {
} }
} }
/// Contains the fields that are returned by a client registration start
pub struct ClientRegistrationStartResult<CS: CipherSuite> {
/// The registration request message to be sent to the server
pub message: RegistrationRequest<CS::Group>,
/// The client state that must be persisted in order to complete registration
pub state: ClientRegistration<CS>,
}
impl<CS: CipherSuite> ClientRegistration<CS> { impl<CS: CipherSuite> ClientRegistration<CS> {
/// Returns an initial "blinded" request to send to the server, as well as a ClientRegistration /// Returns an initial "blinded" request to send to the server, as well as a ClientRegistration
/// ///
@@ -124,15 +132,15 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// type SlowHash = opaque_ke::slow_hash::NoOpHash; /// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// } /// }
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let (register_m1, registration_state) = ClientRegistration::<Default>::start(b"hunter2", ClientRegistrationStartParameters::default(), &mut client_rng)?; /// let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn start<R: RngCore + CryptoRng>( pub fn start<R: RngCore + CryptoRng>(
blinding_factor_rng: &mut R,
password: &[u8], password: &[u8],
params: ClientRegistrationStartParameters, params: ClientRegistrationStartParameters,
blinding_factor_rng: &mut R,
#[cfg(test)] postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar, #[cfg(test)] postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar,
) -> Result<(RegisterFirstMessage<CS::Group>, Self), ProtocolError> { ) -> Result<ClientRegistrationStartResult<CS>, ProtocolError> {
let (id_u, id_s) = match params { let (id_u, id_s) = match params {
ClientRegistrationStartParameters::WithIdentifiers(id_u, id_s) => (id_u, id_s), ClientRegistrationStartParameters::WithIdentifiers(id_u, id_s) => (id_u, id_s),
}; };
@@ -144,17 +152,20 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
postprocess, postprocess,
)?; )?;
Ok(( Ok(ClientRegistrationStartResult {
RegisterFirstMessage::<CS::Group> { alpha }, message: RegistrationRequest::<CS::Group> { alpha },
Self { id_u, id_s, token }, state: Self { id_u, id_s, token },
)) })
} }
} }
type ClientRegistrationFinishResult<KeyFormat, D> = ( /// Contains the fields that are returned by a client registration finish
RegisterThirdMessage<KeyFormat, D>, pub struct ClientRegistrationFinishResult<KeyFormat: KeyPair, D: Hash> {
GenericArray<u8, ExportKeySize>, /// The registration upload message to be sent to the server
); pub message: RegistrationUpload<KeyFormat, D>,
/// The export key output by client registration
pub export_key: GenericArray<u8, ExportKeySize>,
}
impl<CS: CipherSuite> ClientRegistration<CS> { impl<CS: CipherSuite> ClientRegistration<CS> {
/// "Unblinds" the server's answer and returns a final message containing /// "Unblinds" the server's answer and returns a final message containing
@@ -182,17 +193,17 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let mut server_rng = OsRng; /// let mut server_rng = OsRng;
/// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?; /// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
/// let (register_m1, client_state) = ClientRegistration::<Default>::start(b"hunter2", ClientRegistrationStartParameters::default(), &mut client_rng)?; /// let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// let (register_m2, server_state) = /// let server_registration_start_result =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?; /// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let register_m3 = client_state.finish(register_m2, &mut client_rng)?; /// let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn finish<R: CryptoRng + RngCore>( pub fn finish<R: CryptoRng + RngCore>(
self, self,
r2: RegisterSecondMessage<CS::Group>,
rng: &mut R, rng: &mut R,
r2: RegistrationResponse<CS::Group>,
) -> Result<ClientRegistrationFinishResult<CS::KeyFormat, CS::Hash>, ProtocolError> { ) -> Result<ClientRegistrationFinishResult<CS::KeyFormat, CS::Hash>, ProtocolError> {
let client_static_keypair = CS::KeyFormat::generate_random(rng)?; let client_static_keypair = CS::KeyFormat::generate_random(rng)?;
@@ -215,13 +226,13 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
let (envelope, export_key) = let (envelope, export_key) =
Envelope::<CS::Hash>::seal(&password_derived_key, r2.ecf, credentials_map, rng)?; Envelope::<CS::Hash>::seal(&password_derived_key, r2.ecf, credentials_map, rng)?;
Ok(( Ok(ClientRegistrationFinishResult {
RegisterThirdMessage { message: RegistrationUpload {
envelope, envelope,
client_s_pk: client_static_keypair.public().clone(), client_s_pk: client_static_keypair.public().clone(),
}, },
export_key, export_key,
)) })
} }
} }
@@ -253,6 +264,14 @@ impl<CS: CipherSuite> Drop for ClientLogin<CS> {
} }
} }
/// Contains the fields that are returned by a server registration start
pub struct ServerRegistrationStartResult<CS: CipherSuite> {
/// The registration resposne message to send to the client
pub message: RegistrationResponse<CS::Group>,
/// The state that the server must keep in order to complete registration
pub state: ServerRegistration<CS>,
}
/// The state elements the server holds to record a registration /// The state elements the server holds to record a registration
pub struct ServerRegistration<CS: CipherSuite> { pub struct ServerRegistration<CS: CipherSuite> {
envelope: Option<Envelope<CS::Hash>>, envelope: Option<Envelope<CS::Hash>>,
@@ -351,34 +370,34 @@ where
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let mut server_rng = OsRng; /// let mut server_rng = OsRng;
/// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?; /// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
/// let (register_m1, client_state) = ClientRegistration::<Default>::start(b"hunter2", ClientRegistrationStartParameters::default(), &mut client_rng)?; /// let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// let (register_m2, server_state) = /// let server_registration_start_result =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?; /// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn start<R: RngCore + CryptoRng>( pub fn start<R: RngCore + CryptoRng>(
message: RegisterFirstMessage<CS::Group>,
server_s_pk: &<CS::KeyFormat as KeyPair>::Repr,
rng: &mut R, rng: &mut R,
) -> Result<(RegisterSecondMessage<CS::Group>, Self), ProtocolError> { message: RegistrationRequest<CS::Group>,
server_s_pk: &<CS::KeyFormat as KeyPair>::Repr,
) -> Result<ServerRegistrationStartResult<CS>, ProtocolError> {
// RFC: generate oprf_key (salt) and v_u = g^oprf_key // RFC: generate oprf_key (salt) and v_u = g^oprf_key
let oprf_key = CS::Group::random_scalar(rng); let oprf_key = CS::Group::random_scalar(rng);
// Compute beta = alpha^oprf_key // Compute beta = alpha^oprf_key
let beta = oprf::evaluate::<CS::Group>(message.alpha, &oprf_key); let beta = oprf::evaluate::<CS::Group>(message.alpha, &oprf_key);
Ok(( Ok(ServerRegistrationStartResult {
RegisterSecondMessage { message: RegistrationResponse {
beta, beta,
server_s_pk: server_s_pk.to_arr().to_vec(), server_s_pk: server_s_pk.to_arr().to_vec(),
ecf: EnvelopeCredentialsFormat::default()?, ecf: EnvelopeCredentialsFormat::default()?,
}, },
Self { state: Self {
envelope: None, envelope: None,
client_s_pk: None, client_s_pk: None,
oprf_key, oprf_key,
}, },
)) })
} }
/// From the client's cryptographic identifiers, fully populates and /// From the client's cryptographic identifiers, fully populates and
@@ -405,17 +424,17 @@ where
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let mut server_rng = OsRng; /// let mut server_rng = OsRng;
/// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?; /// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
/// let (register_m1, client_state) = ClientRegistration::<Default>::start(b"hunter2", ClientRegistrationStartParameters::default(), &mut client_rng)?; /// let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// let (register_m2, server_state) = /// let server_registration_start_result =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?; /// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?; /// let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// let client_record = server_state.finish(register_m3)?; /// let client_record = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn finish( pub fn finish(
self, self,
message: RegisterThirdMessage<CS::KeyFormat, CS::Hash>, message: RegistrationUpload<CS::KeyFormat, CS::Hash>,
) -> Result<Self, ProtocolError> { ) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
envelope: Some(message.envelope), envelope: Some(message.envelope),
@@ -511,9 +530,9 @@ impl Default for ClientLoginStartParameters {
/// Contains the fields that are returned by a client login start /// Contains the fields that are returned by a client login start
pub struct ClientLoginStartResult<CS: CipherSuite> { pub struct ClientLoginStartResult<CS: CipherSuite> {
/// The message to send to the server to begin the login protocol /// The message to send to the server to begin the login protocol
pub credential_request: LoginFirstMessage<CS>, pub message: CredentialRequest<CS>,
/// The state that the client must keep in order to complete the protocol /// The state that the client must keep in order to complete the protocol
pub client_login_state: ClientLogin<CS>, pub state: ClientLogin<CS>,
} }
/// Optional parameters for client login finish /// Optional parameters for client login finish
@@ -530,20 +549,20 @@ impl Default for ClientLoginFinishParameters {
/// Contains the fields that are returned by a client login finish /// Contains the fields that are returned by a client login finish
pub struct ClientLoginFinishResult<CS: CipherSuite> { pub struct ClientLoginFinishResult<CS: CipherSuite> {
/// The plaintext info sent by the client
pub plain_info: Vec<u8>,
/// The message to send back to the client
pub confidential_info: Vec<u8>,
/// The message to send to the server to complete the protocol /// The message to send to the server to complete the protocol
pub key_exchange: LoginThirdMessage<CS>, pub message: CredentialFinalization<CS>,
/// The shared session secret /// The shared session secret
pub session_secret: Vec<u8>, pub shared_secret: Vec<u8>,
/// The client-side export key /// The client-side export key
pub export_key: GenericArray<u8, ExportKeySize>, pub export_key: GenericArray<u8, ExportKeySize>,
/// The server's static public key /// The server's static public key
pub server_s_pk: Vec<u8>, pub server_s_pk: Vec<u8>,
/// An optional id_s if suppleid by the server /// An optional id_s if supplied by the server
pub id_s: Option<Vec<u8>>, pub id_s: Option<Vec<u8>>,
/// The plaintext info sent by the client
pub plain_info: Vec<u8>,
/// The confidential info sent by the client
pub confidential_info: Vec<u8>,
} }
impl<CS: CipherSuite> ClientLogin<CS> { impl<CS: CipherSuite> ClientLogin<CS> {
@@ -568,12 +587,12 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// type SlowHash = opaque_ke::slow_hash::NoOpHash; /// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// } /// }
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let client_login_start_result = ClientLogin::<Default>::start(b"hunter2", &mut client_rng, ClientLoginStartParameters::default())?; /// let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"hunter2", ClientLoginStartParameters::default())?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn start<R: RngCore + CryptoRng>( pub fn start<R: RngCore + CryptoRng>(
password: &[u8],
rng: &mut R, rng: &mut R,
password: &[u8],
params: ClientLoginStartParameters, params: ClientLoginStartParameters,
#[cfg(test)] postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar, #[cfg(test)] postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar,
) -> Result<ClientLoginStartResult<CS>, ProtocolError> { ) -> Result<ClientLoginStartResult<CS>, ProtocolError> {
@@ -594,11 +613,11 @@ impl<CS: CipherSuite> ClientLogin<CS> {
let (ke1_state, ke1_message) = let (ke1_state, ke1_message) =
CS::KeyExchange::generate_ke1(alpha.to_arr().to_vec(), info, rng)?; CS::KeyExchange::generate_ke1(alpha.to_arr().to_vec(), info, rng)?;
let l1 = LoginFirstMessage { alpha, ke1_message }; let l1 = CredentialRequest { alpha, ke1_message };
Ok(ClientLoginStartResult { Ok(ClientLoginStartResult {
credential_request: l1, message: l1,
client_login_state: Self { state: Self {
id_u, id_u,
id_s, id_s,
token, token,
@@ -632,19 +651,19 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// } /// }
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// # let mut server_rng = OsRng; /// # let mut server_rng = OsRng;
/// # let (register_m1, client_state) = ClientRegistration::<Default>::start(b"hunter2", ClientRegistrationStartParameters::default(), &mut client_rng)?; /// # let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?; /// # let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
/// # let (register_m2, server_state) = ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?; /// # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?; /// # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// # let p_file = server_state.finish(register_m3)?; /// # let p_file = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// let client_login_start_result = ClientLogin::<Default>::start(b"hunter2", &mut client_rng, ClientLoginStartParameters::default())?; /// let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"hunter2", ClientLoginStartParameters::default())?;
/// let server_login_start_result = ServerLogin::start(p_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?; /// let server_login_start_result = ServerLogin::start(&mut server_rng, p_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default())?;
/// let client_login_finish_result = client_login_start_result.client_login_state.finish(server_login_start_result.credential_response, ClientLoginFinishParameters::default())?; /// let client_login_finish_result = client_login_start_result.state.finish(server_login_start_result.message, ClientLoginFinishParameters::default())?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn finish( pub fn finish(
self, self,
l2: LoginSecondMessage<CS>, l2: CredentialResponse<CS>,
params: ClientLoginFinishParameters, params: ClientLoginFinishParameters,
) -> Result<ClientLoginFinishResult<CS>, ProtocolError> { ) -> Result<ClientLoginFinishResult<CS>, ProtocolError> {
let (info, e_info) = match params { let (info, e_info) = match params {
@@ -683,7 +702,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
None => (server_s_pk.to_arr().to_vec(), None), None => (server_s_pk.to_arr().to_vec(), None),
}; };
let (plain_info, confidential_info, session_secret, ke3_message) = let (plain_info, confidential_info, shared_secret, ke3_message) =
CS::KeyExchange::generate_ke3( CS::KeyExchange::generate_ke3(
l2_bytes, l2_bytes,
l2.ke2_message, l2.ke2_message,
@@ -699,8 +718,8 @@ impl<CS: CipherSuite> ClientLogin<CS> {
Ok(ClientLoginFinishResult { Ok(ClientLoginFinishResult {
plain_info, plain_info,
confidential_info, confidential_info,
key_exchange: LoginThirdMessage { ke3_message }, message: CredentialFinalization { ke3_message },
session_secret, shared_secret,
export_key: opened_envelope.export_key, export_key: opened_envelope.export_key,
server_s_pk: server_s_pk.to_arr().to_vec(), server_s_pk: server_s_pk.to_arr().to_vec(),
id_s: ret_id_s, id_s: ret_id_s,
@@ -744,26 +763,28 @@ impl Default for ServerLoginStartParameters {
/// Contains the fields that are returned by a server login start /// Contains the fields that are returned by a server login start
pub struct ServerLoginStartResult<CS: CipherSuite> { pub struct ServerLoginStartResult<CS: CipherSuite> {
/// The plaintext info sent by the client
pub plain_info: Vec<u8>,
/// The message to send back to the client /// The message to send back to the client
pub credential_response: LoginSecondMessage<CS>, pub message: CredentialResponse<CS>,
/// The state that the server must keep in order to finish the protocl /// The state that the server must keep in order to finish the protocl
pub server_login_state: ServerLogin<CS>, pub state: ServerLogin<CS>,
/// The client's static public key /// The client's static public key
pub client_s_pk: Vec<u8>, pub client_s_pk: Vec<u8>,
/// The plaintext info sent by the client
pub plain_info: Vec<u8>,
} }
/// Contains the fields that are returned by a server login finish /// Contains the fields that are returned by a server login finish
pub struct ServerLoginFinishResult { pub struct ServerLoginFinishResult {
/// The shared session secret between client and server
pub shared_secret: Vec<u8>,
/// The plaintext info sent by the client /// The plaintext info sent by the client
pub plain_info: Vec<u8>, pub plain_info: Vec<u8>,
/// The confidential info sent by the client /// The confidential info sent by the client
pub confidential_info: Vec<u8>, pub confidential_info: Vec<u8>,
/// The shared session secret between client and server
pub session_secret: Vec<u8>,
} }
impl ServerLoginFinishResult {}
impl<CS: CipherSuite> ServerLogin<CS> { impl<CS: CipherSuite> ServerLogin<CS> {
/// byte representation for the server's login state /// byte representation for the server's login state
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
@@ -796,20 +817,20 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let mut server_rng = OsRng; /// let mut server_rng = OsRng;
/// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?; /// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
/// # let (register_m1, client_state) = ClientRegistration::<Default>::start(b"hunter2", ClientRegistrationStartParameters::default(), &mut client_rng)?; /// # let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// # let (register_m2, server_state) = /// # let server_registration_start_result =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?; /// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?; /// # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// # let p_file = server_state.finish(register_m3)?; /// # let p_file = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// let client_login_start_result = ClientLogin::<Default>::start(b"hunter2", &mut client_rng, ClientLoginStartParameters::default())?; /// let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"hunter2", ClientLoginStartParameters::default())?;
/// let server_login_start_result = ServerLogin::start(p_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?; /// let server_login_start_result = ServerLogin::start(&mut server_rng, p_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default())?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn start<R: RngCore + CryptoRng>( pub fn start<R: RngCore + CryptoRng>(
rng: &mut R,
password_file: ServerRegistration<CS>, password_file: ServerRegistration<CS>,
server_s_sk: &<CS::KeyFormat as KeyPair>::Repr, server_s_sk: &<CS::KeyFormat as KeyPair>::Repr,
l1: LoginFirstMessage<CS>, l1: CredentialRequest<CS>,
rng: &mut R,
params: ServerLoginStartParameters, params: ServerLoginStartParameters,
) -> Result<ServerLoginStartResult<CS>, ProtocolError> { ) -> Result<ServerLoginStartResult<CS>, ProtocolError> {
let client_s_pk = password_file let client_s_pk = password_file
@@ -853,7 +874,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
e_info, e_info,
)?; )?;
let l2 = LoginSecondMessage { let l2 = CredentialResponse {
beta, beta,
envelope, envelope,
ke2_message, ke2_message,
@@ -861,8 +882,8 @@ impl<CS: CipherSuite> ServerLogin<CS> {
Ok(ServerLoginStartResult { Ok(ServerLoginStartResult {
plain_info, plain_info,
credential_response: l2, message: l2,
server_login_state: Self { state: Self {
_cs: PhantomData, _cs: PhantomData,
ke2_state, ke2_state,
}, },
@@ -896,22 +917,22 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// let mut client_rng = OsRng; /// let mut client_rng = OsRng;
/// let mut server_rng = OsRng; /// let mut server_rng = OsRng;
/// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?; /// let server_kp = X25519KeyPair::generate_random(&mut server_rng)?;
/// # let (register_m1, client_state) = ClientRegistration::<Default>::start(b"hunter2", ClientRegistrationStartParameters::default(), &mut client_rng)?; /// # let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// # let (register_m2, server_state) = /// # let server_registration_start_result =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?; /// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?; /// # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// # let p_file = server_state.finish(register_m3)?; /// # let p_file = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// let client_login_start_result = ClientLogin::<Default>::start(b"hunter2", &mut client_rng, ClientLoginStartParameters::default())?; /// let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"hunter2", ClientLoginStartParameters::default())?;
/// let server_login_start_result = ServerLogin::start(p_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?; /// let server_login_start_result = ServerLogin::start(&mut server_rng, p_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default())?;
/// let client_login_finish_result = client_login_start_result.client_login_state.finish(server_login_start_result.credential_response, ClientLoginFinishParameters::default())?; /// let client_login_finish_result = client_login_start_result.state.finish(server_login_start_result.message, ClientLoginFinishParameters::default())?;
/// let mut server_transport = server_login_start_result.server_login_state.finish(client_login_finish_result.key_exchange)?; /// let mut server_transport = server_login_start_result.state.finish(client_login_finish_result.message)?;
/// # Ok::<(), ProtocolError>(()) /// # Ok::<(), ProtocolError>(())
/// ``` /// ```
pub fn finish( pub fn finish(
&self, &self,
message: LoginThirdMessage<CS>, message: CredentialFinalization<CS>,
) -> Result<ServerLoginFinishResult, ProtocolError> { ) -> Result<ServerLoginFinishResult, ProtocolError> {
let (plain_info, confidential_info, session_secret) = let (plain_info, confidential_info, shared_secret) =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::finish_ke( <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::finish_ke(
message.ke3_message, message.ke3_message,
&self.ke2_state, &self.ke2_state,
@@ -926,7 +947,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
Ok(ServerLoginFinishResult { Ok(ServerLoginFinishResult {
plain_info, plain_info,
confidential_info, confidential_info,
session_secret, shared_secret,
}) })
} }
} }
+12 -12
View File
@@ -121,7 +121,7 @@ fn register_first_message_roundtrip() {
input.extend_from_slice(&alpha_length.to_be_bytes()[std::mem::size_of::<usize>() - 2..]); input.extend_from_slice(&alpha_length.to_be_bytes()[std::mem::size_of::<usize>() - 2..]);
input.extend_from_slice(pt_bytes.as_slice()); input.extend_from_slice(pt_bytes.as_slice());
let r1 = RegisterFirstMessage::<RistrettoPoint>::deserialize(input.as_slice()).unwrap(); let r1 = RegistrationRequest::<RistrettoPoint>::deserialize(input.as_slice()).unwrap();
let r1_bytes = r1.serialize(); let r1_bytes = r1.serialize();
assert_eq!(input, r1_bytes); assert_eq!(input, r1_bytes);
} }
@@ -145,7 +145,7 @@ fn register_second_message_roundtrip() {
input.extend_from_slice(&pubkey_bytes.as_slice()); input.extend_from_slice(&pubkey_bytes.as_slice());
input.extend_from_slice(&credential_types); input.extend_from_slice(&credential_types);
let r2 = RegisterSecondMessage::<RistrettoPoint>::deserialize(input.as_slice()).unwrap(); let r2 = RegistrationResponse::<RistrettoPoint>::deserialize(input.as_slice()).unwrap();
let r2_bytes = r2.serialize(); let r2_bytes = r2.serialize();
assert_eq!(input, r2_bytes); assert_eq!(input, r2_bytes);
} }
@@ -173,7 +173,7 @@ fn register_third_message_roundtrip() {
input.extend_from_slice(&pubkey_length.to_be_bytes()[std::mem::size_of::<usize>() - 2..]); input.extend_from_slice(&pubkey_length.to_be_bytes()[std::mem::size_of::<usize>() - 2..]);
input.extend_from_slice(&pubkey_bytes[..]); input.extend_from_slice(&pubkey_bytes[..]);
let r3 = RegisterThirdMessage::<X25519KeyPair, sha2::Sha256>::deserialize(&input[..]).unwrap(); let r3 = RegistrationUpload::<X25519KeyPair, sha2::Sha256>::deserialize(&input[..]).unwrap();
let r3_bytes = r3.serialize(); let r3_bytes = r3.serialize();
assert_eq!(input, r3_bytes); assert_eq!(input, r3_bytes);
} }
@@ -205,7 +205,7 @@ fn login_first_message_roundtrip() {
input.extend_from_slice(&alpha_bytes); input.extend_from_slice(&alpha_bytes);
input.extend_from_slice(&ke1m[..]); input.extend_from_slice(&ke1m[..]);
let l1 = LoginFirstMessage::<Default>::deserialize(input.as_slice()).unwrap(); let l1 = CredentialRequest::<Default>::deserialize(input.as_slice()).unwrap();
let l1_bytes = l1.serialize(); let l1_bytes = l1.serialize();
assert_eq!(input, l1_bytes); assert_eq!(input, l1_bytes);
} }
@@ -254,7 +254,7 @@ fn login_second_message_roundtrip() {
input.extend_from_slice(&envelope.serialize()); input.extend_from_slice(&envelope.serialize());
input.extend_from_slice(&ke2m[..]); input.extend_from_slice(&ke2m[..]);
let l2 = LoginSecondMessage::<Default>::deserialize(&input).unwrap(); let l2 = CredentialResponse::<Default>::deserialize(&input).unwrap();
let l2_bytes = l2.serialize(); let l2_bytes = l2.serialize();
assert_eq!(input, l2_bytes); assert_eq!(input, l2_bytes);
} }
@@ -276,7 +276,7 @@ fn login_third_message_roundtrip() {
] ]
.concat(); .concat();
let l3 = LoginThirdMessage::<Default>::deserialize(&input).unwrap(); let l3 = CredentialFinalization::<Default>::deserialize(&input).unwrap();
let l3_bytes = l3.serialize(); let l3_bytes = l3.serialize();
assert_eq!(input, l3_bytes); assert_eq!(input, l3_bytes);
} }
@@ -403,32 +403,32 @@ fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..std::mem::size_of::<usize>()))
#[test] #[test]
fn test_nocrash_register_first_message(bytes in vec(any::<u8>(), 0..200)) { fn test_nocrash_register_first_message(bytes in vec(any::<u8>(), 0..200)) {
RegisterFirstMessage::<RistrettoPoint>::try_from(&bytes[..]).map_or(true, |_| true); RegistrationRequest::<RistrettoPoint>::try_from(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_register_second_message(bytes in vec(any::<u8>(), 0..200)) { fn test_nocrash_register_second_message(bytes in vec(any::<u8>(), 0..200)) {
RegisterSecondMessage::<RistrettoPoint>::try_from(&bytes[..]).map_or(true, |_| true); RegistrationResponse::<RistrettoPoint>::try_from(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_register_third_message(bytes in vec(any::<u8>(), 0..200)) { fn test_nocrash_register_third_message(bytes in vec(any::<u8>(), 0..200)) {
RegisterThirdMessage::<crate::keypair::X25519KeyPair, sha2::Sha512>::try_from(&bytes[..]).map_or(true, |_| true); RegistrationUpload::<crate::keypair::X25519KeyPair, sha2::Sha512>::try_from(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_login_first_message(bytes in vec(any::<u8>(), 0..500)) { fn test_nocrash_login_first_message(bytes in vec(any::<u8>(), 0..500)) {
LoginFirstMessage::<Default>::try_from(&bytes[..]).map_or(true, |_| true); CredentialRequest::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_login_second_message(bytes in vec(any::<u8>(), 0..500)) { fn test_nocrash_login_second_message(bytes in vec(any::<u8>(), 0..500)) {
LoginSecondMessage::<Default>::try_from(&bytes[..]).map_or(true, |_| true); CredentialResponse::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
fn test_nocrash_login_third_message(bytes in vec(any::<u8>(), 0..500)) { fn test_nocrash_login_third_message(bytes in vec(any::<u8>(), 0..500)) {
LoginThirdMessage::<Default>::try_from(&bytes[..]).map_or(true, |_| true); CredentialFinalization::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
} }
#[test] #[test]
+183 -128
View File
@@ -55,12 +55,12 @@ pub struct TestVectorParameters {
pub einfo2: Vec<u8>, pub einfo2: Vec<u8>,
pub info3: Vec<u8>, pub info3: Vec<u8>,
pub einfo3: Vec<u8>, pub einfo3: Vec<u8>,
pub r1: Vec<u8>, pub registration_request: Vec<u8>,
pub r2: Vec<u8>, pub registration_response: Vec<u8>,
pub r3: Vec<u8>, pub message: Vec<u8>,
pub l1: Vec<u8>, pub credential_request: Vec<u8>,
pub l2: Vec<u8>, pub credential_response: Vec<u8>,
pub l3: Vec<u8>, pub key_exchange: Vec<u8>,
client_registration_state: Vec<u8>, client_registration_state: Vec<u8>,
server_registration_state: Vec<u8>, server_registration_state: Vec<u8>,
client_login_state: Vec<u8>, client_login_state: Vec<u8>,
@@ -93,12 +93,12 @@ static TEST_VECTOR: &str = r#"
"einfo2": "65696e666f32", "einfo2": "65696e666f32",
"info3": "696e666f33", "info3": "696e666f33",
"einfo3": "65696e666f33", "einfo3": "65696e666f33",
"r1": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b365957", "registration_request": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b365957",
"r2": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa80020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e01010103", "registration_response": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa80020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e01010103",
"r3": "abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed8900205320b55752ad2061c1804050f8a225a4ab1184bc17d8fa6b3c86470c33d9ce42", "message": "abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed8900205320b55752ad2061c1804050f8a225a4ab1184bc17d8fa6b3c86470c33d9ce42",
"l1": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b3659571a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c70005696e666f3177fc3fefb8178ae08461756b54364c4f2d1363d5ce3187af128a3f84a6c5722a", "credential_request": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b3659571a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c70005696e666f3177fc3fefb8178ae08461756b54364c4f2d1363d5ce3187af128a3f84a6c5722a",
"l2": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa8abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed89606034b9be54759ea5802a2dd71e4413e98d52c46e60f2d0868642ad9e6a9b460005696e666f325a314dc389c12bf041b14e131fadebcc98e0fc33d3cd996ad9392c7ae6bff468000665696e666f32661aa1d3e579032df30a78312d38a4c3d8d8a0f1b9bb7bbdbff040e0881a248e", "credential_response": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa8abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed89606034b9be54759ea5802a2dd71e4413e98d52c46e60f2d0868642ad9e6a9b460005696e666f325a314dc389c12bf041b14e131fadebcc98e0fc33d3cd996ad9392c7ae6bff468000665696e666f32661aa1d3e579032df30a78312d38a4c3d8d8a0f1b9bb7bbdbff040e0881a248e",
"l3": "0005696e666f33000665696e666f3317090781af5a220941ddd6db7d4f2af33d9b316a48aee163647131970bae50ba", "key_exchange": "0005696e666f33000665696e666f3317090781af5a220941ddd6db7d4f2af33d9b316a48aee163647131970bae50ba",
"client_registration_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130070617373776f7264", "client_registration_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130070617373776f7264",
"client_login_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130048b452f6d0b28387cfa98245bda9230b6df215ed5b820bffb8511ec6802d80751a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c7288b735853d9e1d8ab699b7c4aef54680f036c56140dc0a4991f6d02a95babc970617373776f7264", "client_login_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130048b452f6d0b28387cfa98245bda9230b6df215ed5b820bffb8511ec6802d80751a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c7288b735853d9e1d8ab699b7c4aef54680f036c56140dc0a4991f6d02a95babc970617373776f7264",
"server_registration_state": "7f1d2a048a7aad9d1cf2b96473e3adbb1e0626eafe0abdfd09f1f700beda9d0f", "server_registration_state": "7f1d2a048a7aad9d1cf2b96473e3adbb1e0626eafe0abdfd09f1f700beda9d0f",
@@ -138,12 +138,12 @@ fn populate_test_vectors(values: &Value) -> TestVectorParameters {
einfo2: decode(&values, "einfo2").unwrap(), einfo2: decode(&values, "einfo2").unwrap(),
info3: decode(&values, "info3").unwrap(), info3: decode(&values, "info3").unwrap(),
einfo3: decode(&values, "einfo3").unwrap(), einfo3: decode(&values, "einfo3").unwrap(),
r1: decode(&values, "r1").unwrap(), registration_request: decode(&values, "registration_request").unwrap(),
r2: decode(&values, "r2").unwrap(), registration_response: decode(&values, "registration_response").unwrap(),
r3: decode(&values, "r3").unwrap(), message: decode(&values, "message").unwrap(),
l1: decode(&values, "l1").unwrap(), credential_request: decode(&values, "credential_request").unwrap(),
l2: decode(&values, "l2").unwrap(), credential_response: decode(&values, "credential_response").unwrap(),
l3: decode(&values, "l3").unwrap(), key_exchange: decode(&values, "key_exchange").unwrap(),
client_registration_state: decode(&values, "client_registration_state").unwrap(), client_registration_state: decode(&values, "client_registration_state").unwrap(),
client_login_state: decode(&values, "client_login_state").unwrap(), client_login_state: decode(&values, "client_login_state").unwrap(),
server_registration_state: decode(&values, "server_registration_state").unwrap(), server_registration_state: decode(&values, "server_registration_state").unwrap(),
@@ -190,12 +190,36 @@ fn stringify_test_vectors(p: &TestVectorParameters) -> String {
s.push_str(format!("\"einfo2\": \"{}\",\n", hex::encode(&p.einfo2)).as_str()); s.push_str(format!("\"einfo2\": \"{}\",\n", hex::encode(&p.einfo2)).as_str());
s.push_str(format!("\"info3\": \"{}\",\n", hex::encode(&p.info3)).as_str()); s.push_str(format!("\"info3\": \"{}\",\n", hex::encode(&p.info3)).as_str());
s.push_str(format!("\"einfo3\": \"{}\",\n", hex::encode(&p.einfo3)).as_str()); s.push_str(format!("\"einfo3\": \"{}\",\n", hex::encode(&p.einfo3)).as_str());
s.push_str(format!("\"r1\": \"{}\",\n", hex::encode(&p.r1)).as_str()); s.push_str(
s.push_str(format!("\"r2\": \"{}\",\n", hex::encode(&p.r2)).as_str()); format!(
s.push_str(format!("\"r3\": \"{}\",\n", hex::encode(&p.r3)).as_str()); "\"registration_request\": \"{}\",\n",
s.push_str(format!("\"l1\": \"{}\",\n", hex::encode(&p.l1)).as_str()); hex::encode(&p.registration_request)
s.push_str(format!("\"l2\": \"{}\",\n", hex::encode(&p.l2)).as_str()); )
s.push_str(format!("\"l3\": \"{}\",\n", hex::encode(&p.l3)).as_str()); .as_str(),
);
s.push_str(
format!(
"\"registration_response\": \"{}\",\n",
hex::encode(&p.registration_response)
)
.as_str(),
);
s.push_str(format!("\"message\": \"{}\",\n", hex::encode(&p.message)).as_str());
s.push_str(
format!(
"\"credential_request\": \"{}\",\n",
hex::encode(&p.credential_request)
)
.as_str(),
);
s.push_str(
format!(
"\"credential_response\": \"{}\",\n",
hex::encode(&p.credential_response)
)
.as_str(),
);
s.push_str(format!("\"key_exchange\": \"{}\",\n", hex::encode(&p.key_exchange)).as_str());
s.push_str( s.push_str(
format!( format!(
"\"client_registration_state\": \"{}\",\n", "\"client_registration_state\": \"{}\",\n",
@@ -277,36 +301,57 @@ where
let einfo3 = b"einfo3"; let einfo3 = b"einfo3";
let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_raw.to_vec()); let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_raw.to_vec());
let (r1, client_registration) = ClientRegistration::<CS>::start( let client_registration_start_result = ClientRegistration::<CS>::start(
&mut blinding_factor_registration_rng,
password, password,
ClientRegistrationStartParameters::WithIdentifiers(id_u.to_vec(), id_s.to_vec()), ClientRegistrationStartParameters::WithIdentifiers(id_u.to_vec(), id_s.to_vec()),
&mut blinding_factor_registration_rng,
std::convert::identity, std::convert::identity,
) )
.unwrap(); .unwrap();
let r1_bytes = r1.serialize().to_vec(); let registration_request_bytes = client_registration_start_result
.message
.serialize()
.to_vec();
let blinding_factor_bytes = let blinding_factor_bytes =
CS::Group::scalar_as_bytes(&client_registration.token.blind).clone(); CS::Group::scalar_as_bytes(&client_registration_start_result.state.token.blind).clone();
let client_registration_state = client_registration.to_bytes().to_vec(); let client_registration_state = client_registration_start_result.state.to_bytes().to_vec();
let mut oprf_key_rng = CycleRng::new(oprf_key_raw.to_vec()); let mut oprf_key_rng = CycleRng::new(oprf_key_raw.to_vec());
let (r2, server_registration) = let server_registration_start_result = ServerRegistration::<CS>::start(
ServerRegistration::<CS>::start(r1, server_s_kp.public(), &mut oprf_key_rng).unwrap(); &mut oprf_key_rng,
let r2_bytes = r2.serialize().to_vec(); client_registration_start_result.message,
let oprf_key_bytes = CS::Group::scalar_as_bytes(&server_registration.oprf_key).clone(); server_s_kp.public(),
let server_registration_state = server_registration.to_bytes().to_vec(); )
.unwrap();
let registration_response_bytes = server_registration_start_result
.message
.serialize()
.to_vec();
let oprf_key_bytes =
CS::Group::scalar_as_bytes(&server_registration_start_result.state.oprf_key).clone();
let server_registration_state = server_registration_start_result.state.to_bytes().to_vec();
let mut client_s_sk_and_nonce: Vec<u8> = Vec::new(); let mut client_s_sk_and_nonce: Vec<u8> = Vec::new();
client_s_sk_and_nonce.extend_from_slice(&client_s_kp.private().to_arr()); client_s_sk_and_nonce.extend_from_slice(&client_s_kp.private().to_arr());
client_s_sk_and_nonce.extend_from_slice(&envelope_nonce); client_s_sk_and_nonce.extend_from_slice(&envelope_nonce);
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce); let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
let (r3, export_key_registration) = client_registration let client_registration_finish_result = client_registration_start_result
.finish(r2, &mut finish_registration_rng) .state
.finish(
&mut finish_registration_rng,
server_registration_start_result.message,
)
.unwrap(); .unwrap();
let r3_bytes = r3.serialize().to_vec(); let message_bytes = client_registration_finish_result
.message
.serialize()
.to_vec();
let password_file = server_registration.finish(r3).unwrap(); let password_file = server_registration_start_result
.state
.finish(client_registration_finish_result.message)
.unwrap();
let password_file_bytes = password_file.to_bytes(); let password_file_bytes = password_file.to_bytes();
let mut client_login_start: Vec<u8> = Vec::new(); let mut client_login_start: Vec<u8> = Vec::new();
@@ -316,8 +361,8 @@ where
let mut client_login_start_rng = CycleRng::new(client_login_start); let mut client_login_start_rng = CycleRng::new(client_login_start);
let client_login_start_result = ClientLogin::<CS>::start( let client_login_start_result = ClientLogin::<CS>::start(
password,
&mut client_login_start_rng, &mut client_login_start_rng,
password,
ClientLoginStartParameters::WithInfoAndIdentifiers( ClientLoginStartParameters::WithInfoAndIdentifiers(
info1.to_vec(), info1.to_vec(),
id_u.to_vec(), id_u.to_vec(),
@@ -326,41 +371,29 @@ where
std::convert::identity, std::convert::identity,
) )
.unwrap(); .unwrap();
let l1_bytes = client_login_start_result let credential_request_bytes = client_login_start_result.message.serialize().to_vec();
.credential_request let client_login_state = client_login_start_result.state.to_bytes().to_vec();
.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 mut server_e_sk_rng = CycleRng::new(server_e_kp.private().to_arr().to_vec());
let server_login_start_result = ServerLogin::<CS>::start( let server_login_start_result = ServerLogin::<CS>::start(
&mut server_e_sk_rng,
password_file, password_file,
server_s_kp.private(), server_s_kp.private(),
client_login_start_result.credential_request, client_login_start_result.message,
&mut server_e_sk_rng,
ServerLoginStartParameters::WithInfo(info2.to_vec(), einfo2.to_vec()), ServerLoginStartParameters::WithInfo(info2.to_vec(), einfo2.to_vec()),
) )
.unwrap(); .unwrap();
let l2_bytes = server_login_start_result let credential_response_bytes = server_login_start_result.message.serialize().to_vec();
.credential_response let server_login_state = server_login_start_result.state.to_bytes().to_vec();
.serialize()
.to_vec();
let server_login_state = server_login_start_result
.server_login_state
.to_bytes()
.to_vec();
let client_login_finish_result = client_login_start_result let client_login_finish_result = client_login_start_result
.client_login_state .state
.finish( .finish(
server_login_start_result.credential_response, server_login_start_result.message,
ClientLoginFinishParameters::WithInfo(info3.to_vec(), einfo3.to_vec()), ClientLoginFinishParameters::WithInfo(info3.to_vec(), einfo3.to_vec()),
) )
.unwrap(); .unwrap();
let l3_bytes = client_login_finish_result.key_exchange.to_bytes().to_vec(); let key_exchange_bytes = client_login_finish_result.message.to_bytes().to_vec();
TestVectorParameters { TestVectorParameters {
client_s_pk: client_s_kp.public().to_arr().to_vec(), client_s_pk: client_s_kp.public().to_arr().to_vec(),
@@ -384,19 +417,19 @@ where
einfo2: einfo2.to_vec(), einfo2: einfo2.to_vec(),
info3: info3.to_vec(), info3: info3.to_vec(),
einfo3: einfo3.to_vec(), einfo3: einfo3.to_vec(),
r1: r1_bytes, registration_request: registration_request_bytes,
r2: r2_bytes, registration_response: registration_response_bytes,
r3: r3_bytes, message: message_bytes,
l1: l1_bytes, credential_request: credential_request_bytes,
l2: l2_bytes, credential_response: credential_response_bytes,
l3: l3_bytes, key_exchange: key_exchange_bytes,
password_file: password_file_bytes, password_file: password_file_bytes,
client_registration_state, client_registration_state,
server_registration_state, server_registration_state,
client_login_state, client_login_state,
server_login_state, server_login_state,
shared_secret: client_login_finish_result.session_secret, shared_secret: client_login_finish_result.shared_secret,
export_key: export_key_registration.to_vec(), export_key: client_registration_finish_result.export_key.to_vec(),
} }
} }
@@ -413,58 +446,68 @@ fn postprocess_blinding_factor<G: Group>(_: G::Scalar) -> G::Scalar {
} }
#[test] #[test]
fn test_r1() -> Result<(), ProtocolError> { fn test_registration_request() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let mut rng = OsRng; let mut rng = OsRng;
let (r1, client_registration) = ClientRegistration::<X255193dhNoSlowHash>::start( let client_registration_start_result = ClientRegistration::<X255193dhNoSlowHash>::start(
&mut rng,
&parameters.password, &parameters.password,
ClientRegistrationStartParameters::WithIdentifiers(parameters.id_u, parameters.id_s), ClientRegistrationStartParameters::WithIdentifiers(parameters.id_u, parameters.id_s),
&mut rng,
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>, postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
)?; )?;
assert_eq!(hex::encode(&parameters.r1), hex::encode(r1.serialize())); assert_eq!(
hex::encode(&parameters.registration_request),
hex::encode(client_registration_start_result.message.serialize())
);
assert_eq!( assert_eq!(
hex::encode(&parameters.client_registration_state), hex::encode(&parameters.client_registration_state),
hex::encode(client_registration.to_bytes()) hex::encode(client_registration_start_result.state.to_bytes())
); );
Ok(()) Ok(())
} }
#[test] #[test]
fn test_r2() -> Result<(), ProtocolError> { fn test_registration_response() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let mut oprf_key_rng = CycleRng::new(parameters.oprf_key); let mut oprf_key_rng = CycleRng::new(parameters.oprf_key);
let (r2, server_registration) = ServerRegistration::<X255193dhNoSlowHash>::start( let server_registration_start_result = ServerRegistration::<X255193dhNoSlowHash>::start(
RegisterFirstMessage::deserialize(&parameters.r1[..]).unwrap(),
&Key::try_from(&parameters.server_s_pk[..]).unwrap(),
&mut oprf_key_rng, &mut oprf_key_rng,
RegistrationRequest::deserialize(&parameters.registration_request[..]).unwrap(),
&Key::try_from(&parameters.server_s_pk[..]).unwrap(),
)?; )?;
assert_eq!(hex::encode(parameters.r2), hex::encode(r2.serialize())); assert_eq!(
hex::encode(parameters.registration_response),
hex::encode(server_registration_start_result.message.serialize())
);
assert_eq!( assert_eq!(
hex::encode(&parameters.server_registration_state), hex::encode(&parameters.server_registration_state),
hex::encode(server_registration.to_bytes()) hex::encode(server_registration_start_result.state.to_bytes())
); );
Ok(()) Ok(())
} }
#[test] #[test]
fn test_r3() -> Result<(), ProtocolError> { fn test_message() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let client_s_sk_and_nonce: Vec<u8> = let client_s_sk_and_nonce: Vec<u8> =
[parameters.client_s_sk, parameters.envelope_nonce].concat(); [parameters.client_s_sk, parameters.envelope_nonce].concat();
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce); let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
let (r3, export_key_registration) = ClientRegistration::<X255193dhNoSlowHash>::try_from( let result = ClientRegistration::<X255193dhNoSlowHash>::try_from(
&parameters.client_registration_state[..], &parameters.client_registration_state[..],
)? )?
.finish( .finish(
RegisterSecondMessage::deserialize(&parameters.r2[..]).unwrap(),
&mut finish_registration_rng, &mut finish_registration_rng,
RegistrationResponse::deserialize(&parameters.registration_response[..]).unwrap(),
)?; )?;
assert_eq!(hex::encode(parameters.r3), hex::encode(r3.serialize()));
assert_eq!(
hex::encode(parameters.message),
hex::encode(result.message.serialize())
);
assert_eq!( assert_eq!(
hex::encode(parameters.export_key), hex::encode(parameters.export_key),
hex::encode(export_key_registration.to_vec()) hex::encode(result.export_key.to_vec())
); );
Ok(()) Ok(())
@@ -478,7 +521,8 @@ fn test_password_file() -> Result<(), ProtocolError> {
&parameters.server_registration_state[..], &parameters.server_registration_state[..],
)?; )?;
let password_file = server_registration let password_file = server_registration
.finish(RegisterThirdMessage::deserialize(&parameters.r3[..]).unwrap())?; .finish(RegistrationUpload::deserialize(&parameters.message[..]).unwrap())?;
assert_eq!( assert_eq!(
hex::encode(parameters.password_file), hex::encode(parameters.password_file),
hex::encode(password_file.to_bytes()) hex::encode(password_file.to_bytes())
@@ -487,7 +531,7 @@ fn test_password_file() -> Result<(), ProtocolError> {
} }
#[test] #[test]
fn test_l1() -> Result<(), ProtocolError> { fn test_credential_request() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let client_login_start = [ let client_login_start = [
@@ -498,8 +542,8 @@ fn test_l1() -> Result<(), ProtocolError> {
.concat(); .concat();
let mut client_login_start_rng = CycleRng::new(client_login_start); let mut client_login_start_rng = CycleRng::new(client_login_start);
let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start( let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start(
&parameters.password,
&mut client_login_start_rng, &mut client_login_start_rng,
&parameters.password,
ClientLoginStartParameters::WithInfoAndIdentifiers( ClientLoginStartParameters::WithInfoAndIdentifiers(
parameters.info1, parameters.info1,
parameters.id_u, parameters.id_u,
@@ -508,26 +552,27 @@ fn test_l1() -> Result<(), ProtocolError> {
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>, postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
)?; )?;
assert_eq!( assert_eq!(
hex::encode(&parameters.l1), hex::encode(&parameters.credential_request),
hex::encode(client_login_start_result.credential_request.serialize()) hex::encode(client_login_start_result.message.serialize())
); );
assert_eq!( assert_eq!(
hex::encode(&parameters.client_login_state), hex::encode(&parameters.client_login_state),
hex::encode(client_login_start_result.client_login_state.to_bytes()) hex::encode(client_login_start_result.state.to_bytes())
); );
Ok(()) Ok(())
} }
#[test] #[test]
fn test_l2() -> Result<(), ProtocolError> { fn test_credential_response() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); 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 mut server_e_sk_rng = CycleRng::new(parameters.server_e_sk);
let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start( let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start(
&mut server_e_sk_rng,
ServerRegistration::try_from(&parameters.password_file[..]).unwrap(), ServerRegistration::try_from(&parameters.password_file[..]).unwrap(),
&Key::try_from(&parameters.server_s_sk[..]).unwrap(), &Key::try_from(&parameters.server_s_sk[..]).unwrap(),
LoginFirstMessage::<X255193dhNoSlowHash>::deserialize(&parameters.l1[..]).unwrap(), CredentialRequest::<X255193dhNoSlowHash>::deserialize(&parameters.credential_request[..])
&mut server_e_sk_rng, .unwrap(),
ServerLoginStartParameters::WithInfo(parameters.info2.to_vec(), parameters.einfo2.to_vec()), ServerLoginStartParameters::WithInfo(parameters.info2.to_vec(), parameters.einfo2.to_vec()),
)?; )?;
assert_eq!( assert_eq!(
@@ -539,28 +584,33 @@ fn test_l2() -> Result<(), ProtocolError> {
hex::encode(server_login_start_result.client_s_pk), hex::encode(server_login_start_result.client_s_pk),
); );
assert_eq!( assert_eq!(
hex::encode(&parameters.l2), hex::encode(&parameters.credential_response),
hex::encode(server_login_start_result.credential_response.serialize()) hex::encode(server_login_start_result.message.serialize())
); );
assert_eq!( assert_eq!(
hex::encode(&parameters.server_login_state), hex::encode(&parameters.server_login_state),
hex::encode(server_login_start_result.server_login_state.to_bytes()) hex::encode(server_login_start_result.state.to_bytes())
); );
Ok(()) Ok(())
} }
#[test] #[test]
fn test_l3() -> Result<(), ProtocolError> { fn test_key_exchange() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let client_login_finish_result = let client_login_finish_result =
ClientLogin::<X255193dhNoSlowHash>::try_from(&parameters.client_login_state[..])?.finish( ClientLogin::<X255193dhNoSlowHash>::try_from(&parameters.client_login_state[..])
LoginSecondMessage::<X255193dhNoSlowHash>::deserialize(&parameters.l2[..]).unwrap(), .unwrap()
ClientLoginFinishParameters::WithInfo( .finish(
parameters.info3.to_vec(), CredentialResponse::<X255193dhNoSlowHash>::deserialize(
parameters.einfo3.to_vec(), &parameters.credential_response[..],
), )?,
)?; ClientLoginFinishParameters::WithInfo(
parameters.info3.to_vec(),
parameters.einfo3.to_vec(),
),
)?;
assert_eq!( assert_eq!(
hex::encode(&parameters.info2), hex::encode(&parameters.info2),
hex::encode(&client_login_finish_result.plain_info) hex::encode(&client_login_finish_result.plain_info)
@@ -576,11 +626,11 @@ fn test_l3() -> Result<(), ProtocolError> {
assert_eq!(None, client_login_finish_result.id_s); assert_eq!(None, client_login_finish_result.id_s);
assert_eq!( assert_eq!(
hex::encode(&parameters.shared_secret), hex::encode(&parameters.shared_secret),
hex::encode(&client_login_finish_result.session_secret) hex::encode(&client_login_finish_result.shared_secret)
); );
assert_eq!( assert_eq!(
hex::encode(&parameters.l3), hex::encode(&parameters.key_exchange),
hex::encode(client_login_finish_result.key_exchange.to_bytes()) hex::encode(client_login_finish_result.message.to_bytes())
); );
assert_eq!( assert_eq!(
hex::encode(&parameters.export_key), hex::encode(&parameters.export_key),
@@ -595,8 +645,10 @@ fn test_server_login_finish() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let server_login_result = let server_login_result =
ServerLogin::<X255193dhNoSlowHash>::try_from(&parameters.server_login_state[..])? ServerLogin::<X255193dhNoSlowHash>::try_from(&parameters.server_login_state[..])?.finish(
.finish(LoginThirdMessage::try_from(&parameters.l3[..])?)?; CredentialFinalization::try_from(&parameters.key_exchange[..])?,
)?;
assert_eq!( assert_eq!(
hex::encode(parameters.info3), hex::encode(parameters.info3),
hex::encode(server_login_result.plain_info) hex::encode(server_login_result.plain_info)
@@ -607,7 +659,7 @@ fn test_server_login_finish() -> Result<(), ProtocolError> {
); );
assert_eq!( assert_eq!(
hex::encode(parameters.shared_secret), hex::encode(parameters.shared_secret),
hex::encode(server_login_result.session_secret) hex::encode(server_login_result.shared_secret)
); );
Ok(()) Ok(())
@@ -620,51 +672,54 @@ fn test_complete_flow(
let mut client_rng = OsRng; let mut client_rng = OsRng;
let mut server_rng = OsRng; let mut server_rng = OsRng;
let server_kp = X255193dhNoSlowHash::generate_random_keypair(&mut server_rng)?; let server_kp = X255193dhNoSlowHash::generate_random_keypair(&mut server_rng)?;
let (register_m1, client_state) = ClientRegistration::<X255193dhNoSlowHash>::start( let client_registration_start_result = ClientRegistration::<X255193dhNoSlowHash>::start(
&mut client_rng,
registration_password, registration_password,
ClientRegistrationStartParameters::default(), ClientRegistrationStartParameters::default(),
&mut client_rng,
std::convert::identity, std::convert::identity,
)?; )?;
let (register_m2, server_state) = ServerRegistration::<X255193dhNoSlowHash>::start( let server_registration_start_result = ServerRegistration::<X255193dhNoSlowHash>::start(
register_m1,
server_kp.public(),
&mut server_rng, &mut server_rng,
client_registration_start_result.message,
server_kp.public(),
)?; )?;
let (register_m3, registration_export_key) = let client_registration_finish_result = client_registration_start_result
client_state.finish(register_m2, &mut client_rng)?; .state
let p_file = server_state.finish(register_m3)?; .finish(&mut client_rng, server_registration_start_result.message)?;
let p_file = server_registration_start_result
.state
.finish(client_registration_finish_result.message)?;
let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start( let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start(
login_password,
&mut client_rng, &mut client_rng,
login_password,
ClientLoginStartParameters::default(), ClientLoginStartParameters::default(),
std::convert::identity, std::convert::identity,
)?; )?;
let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start( let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start(
&mut server_rng,
p_file, p_file,
&server_kp.private(), &server_kp.private(),
client_login_start_result.credential_request, client_login_start_result.message,
&mut server_rng,
ServerLoginStartParameters::default(), ServerLoginStartParameters::default(),
)?; )?;
let client_login_result = client_login_start_result.client_login_state.finish( let client_login_result = client_login_start_result.state.finish(
server_login_start_result.credential_response, server_login_start_result.message,
ClientLoginFinishParameters::default(), ClientLoginFinishParameters::default(),
); );
if hex::encode(registration_password) == hex::encode(login_password) { if hex::encode(registration_password) == hex::encode(login_password) {
let client_login_finish_result = client_login_result?; let client_login_finish_result = client_login_result?;
let server_login_finish_result = server_login_start_result let server_login_finish_result = server_login_start_result
.server_login_state .state
.finish(client_login_finish_result.key_exchange)?; .finish(client_login_finish_result.message)?;
assert_eq!( assert_eq!(
hex::encode(server_login_finish_result.session_secret), hex::encode(server_login_finish_result.shared_secret),
hex::encode(client_login_finish_result.session_secret) hex::encode(client_login_finish_result.shared_secret)
); );
assert_eq!( assert_eq!(
hex::encode(registration_export_key), hex::encode(client_registration_finish_result.export_key),
hex::encode(client_login_finish_result.export_key) hex::encode(client_login_finish_result.export_key)
); );
} else { } else {