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
- [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
Contributors
@@ -41,7 +42,7 @@ To learn more about contributing to this project, [see this document](./CONTRIBU
#### 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.
+33 -31
View File
@@ -30,8 +30,8 @@ use std::process::exit;
use opaque_ke::{
ciphersuite::CipherSuite, keypair::KeyPair, ClientLogin, ClientLoginFinishParameters,
ClientLoginStartParameters, ClientRegistration, ClientRegistrationStartParameters,
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage,
RegisterSecondMessage, RegisterThirdMessage, ServerLogin, ServerLoginStartParameters,
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegistrationResponse, RegistrationUpload, ServerLogin, ServerLoginStartParameters,
ServerRegistration,
};
@@ -53,39 +53,41 @@ fn account_registration(
password: String,
) -> Vec<u8> {
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(),
ClientRegistrationStartParameters::default(),
&mut client_rng,
)
.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 (r2, server_state) = ServerRegistration::<Default>::start(
RegisterFirstMessage::deserialize(&r1_bytes[..]).unwrap(),
server_kp.public(),
let server_registration_start_result = ServerRegistration::<Default>::start(
&mut server_rng,
RegistrationRequest::deserialize(&registration_request_bytes[..]).unwrap(),
server_kp.public(),
)
.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(
RegisterSecondMessage::deserialize(&r2_bytes[..]).unwrap(),
&mut client_rng,
RegistrationResponse::deserialize(&registration_response_bytes[..]).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
.finish(RegisterThirdMessage::deserialize(&r3_bytes[..]).unwrap())
let password_file = server_registration_start_result
.state
.finish(RegistrationUpload::deserialize(&message_bytes[..]).unwrap())
.unwrap();
password_file.to_bytes()
}
@@ -98,31 +100,31 @@ fn account_login(
) -> bool {
let mut client_rng = OsRng;
let client_login_start_result = ClientLogin::<Default>::start(
password.as_bytes(),
&mut client_rng,
password.as_bytes(),
ClientLoginStartParameters::default(),
)
.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 mut server_rng = OsRng;
let server_login_start_result = ServerLogin::start(
&mut server_rng,
password_file,
&server_kp.private(),
LoginFirstMessage::deserialize(&l1_bytes[..]).unwrap(),
&mut server_rng,
CredentialRequest::deserialize(&credential_request_bytes[..]).unwrap(),
ServerLoginStartParameters::default(),
)
.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(
LoginSecondMessage::deserialize(&l2_bytes[..]).unwrap(),
let result = client_login_start_result.state.finish(
CredentialResponse::deserialize(&credential_response_bytes[..]).unwrap(),
ClientLoginFinishParameters::default(),
);
@@ -131,16 +133,16 @@ fn account_login(
return false;
}
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
.server_login_state
.finish(LoginThirdMessage::deserialize(&l3_bytes[..]).unwrap())
.state
.finish(CredentialFinalization::deserialize(&credential_finalization_bytes[..]).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
+131 -108
View File
@@ -5,7 +5,7 @@
//! 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.
//!
//! # Overview
@@ -32,13 +32,11 @@
//! ```
//!
//! 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`.
//!
//! 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.
//! 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.
//!
//! ## 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::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.
//!
//! ## Registration
//! The registration protocol between the client and server consists of four steps along with three messages, denoted
//! as `r1`, `r2`, and `r3`. Before registration begins, it is expected that the server's static public key, `server_kp.public()`,
//! 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 tuple combination of (password, pepper, server public key) provided by
//! The registration protocol between the client and server consists of four steps along with three messages:
//! [RegistrationRequest], [RegistrationResponse], and [RegistrationUpload]. A successful execution of the registration protocol results in the
//! server producing a password file corresponding to the password provided by
//! 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
//! runs `ClientRegistration::start` to produce a message `r1`:
//! ### Client Registration Start
//! 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::{
//! # errors::ProtocolError,
@@ -87,18 +86,20 @@
//! use opaque_ke::{ClientRegistration, ClientRegistrationStartParameters};
//! use rand_core::{OsRng, RngCore};
//! 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",
//! ClientRegistrationStartParameters::default(),
//! &mut client_rng,
//! )?;
//! # 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
//! `ServerRegistration::start` to produce `r2`:
//! ### Server Registration Start
//! 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::{
//! # errors::ProtocolError,
@@ -117,23 +118,28 @@
//! # }
//! # use rand_core::{OsRng, RngCore};
//! # 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",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! use opaque_ke::ServerRegistration;
//! let mut server_rng = OsRng;
//! 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>(())
//! ```
//! `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
//! with the server's static public key `server_kp.public()`, and uses `client_state` from the first step to run
//! `finish` and produce a message `r3` along with the export key `export_key_registration`:
//! ### Client Registration Finish
//! In the third step of registration, the client takes as input
//! 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::{
//! # errors::ProtocolError,
@@ -152,23 +158,28 @@
//! # }
//! # use rand_core::{OsRng, RngCore};
//! # 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",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! let (r3, export_key_registration) =
//! client_state.finish(r2, &mut client_rng)?;
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! let client_registration_finish_result = client_registration_start_result.state.finish(
//! &mut client_rng,
//! server_registration_start_result.message,
//! )?;
//! # 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_state` from the second step to run `finish` and produce `password_file`:
//! ### Server Registration Finish
//! 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::{
//! # errors::ProtocolError,
@@ -187,35 +198,36 @@
//! # }
//! # use rand_core::{OsRng, RngCore};
//! # 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",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?;
//! let password_file = server_state.finish(r3)?;
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! let password_file = server_registration_start_result.state.finish(
//! client_registration_finish_result.message,
//! )?;
//! # 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
//! The login protocol between a client and server also consists of four steps along with three messages, denoted as
//! `l1`, `l2`, and `l3`. The server is expected to have access to the a password file corresponding to an output
//! of the registration phase. The login protocol will execute successfully only if the same tuple combination of
//! (password, pepper, server public key) is presented as was used in the registration phase that produced the
//! password file that the server is testing against.
//! The login protocol between a client and server also consists of four steps along with three messages:
//! [CredentialRequest], [CredentialResponse], [CredentialFinalization]. The server is expected to have access to the password file
//! corresponding to an output of the registration phase. The login protocol will execute successfully only if the same password
//! was used in the registration phase that produced the 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
//! `ClientLogin::start` to produce a message `l1`:
//! ### Client Login Start
//! 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::{
//! # errors::ProtocolError,
//! # ClientRegistration, ServerRegistration, ServerLogin, LoginThirdMessage,
//! # ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -232,22 +244,25 @@
//! use opaque_ke::{ClientLogin, ClientLoginStartParameters};
//! let mut client_rng = OsRng;
//! let client_login_start_result = ClientLogin::<Default>::start(
//! b"password",
//! &mut client_rng,
//! b"password",
//! ClientLoginStartParameters::default(),
//! )?;
//! # 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
//! private key `server_kp.private()`, along with a serialized version of the password file, `password_file_bytes`, and
//! runs `ServerLogin::start` to produce `server_login_start_result`:
//! ### Server Login Start
//! In the second step of login, the server takes as input
//! 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::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, LoginThirdMessage,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -262,39 +277,44 @@
//! # }
//! # use rand_core::{OsRng, RngCore};
//! # 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",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! # 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(
//! # b"password",
//! # &mut client_rng,
//! # b"password",
//! # ClientLoginStartParameters::default(),
//! # )?;
//! use opaque_ke::{ServerLogin, ServerLoginStartParameters};
//! use std::convert::TryFrom;
//! let password_file = ServerRegistration::<Default>::try_from(&password_file_bytes[..])?;
//! let mut server_rng = OsRng;
//! let server_login_start_result =
//! ServerLogin::start(password_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,
//! password_file,
//! &server_kp.private(),
//! client_login_start_result.message,
//! ServerLoginStartParameters::default(),
//! )?;
//! # 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
//! server's static public key `server_kp.public()`, and uses `client_state` from the first step to run `finish` and produce
//! a message `l3`, the shared secret `client_shared_secret`, and the export key `export_key_login`:
//! ### Client Login Finish
//! In the third step of login, the client takes as input a [CredentialResponse] from the server.
//! 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::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -309,20 +329,20 @@
//! # }
//! # use rand_core::{OsRng, RngCore};
//! # 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",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key_registration) = client_state.finish(r2, &mut client_rng)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! # 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(
//! # b"password",
//! # &mut client_rng,
//! # ClientLoginStartParameters::default(),
//! # &mut client_rng,
//! # b"password",
//! # ClientLoginStartParameters::default(),
//! # )?;
//! # use std::convert::TryFrom;
//! # let password_file =
@@ -330,27 +350,25 @@
//! # &password_file_bytes[..],
//! # )?;
//! # let server_login_start_result =
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
//! let client_login_finish_result = client_login_start_result.client_login_state.finish(
//! server_login_start_result.credential_response,
//! # 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.state.finish(
//! server_login_start_result.message,
//! 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>(())
//! ```
//! 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
//! can use `export_key_login` for applications that can take advantage of the fact that this key is identical to
//! `export_key_registration`.
//!
//! 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`:
//! ### Server Login Finish
//! In the fourth step of login, the server takes as input a [CredentialFinalization] from the client and runs [ServerLogin::finish] to
//! produce an output consisting of the `shared_secret` sequence of bytes which will match the client's shared secret upon a successful login.
//! ```
//! # use opaque_ke::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage,
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization,
//! # keypair::{KeyPair, X25519KeyPair},
//! # slow_hash::NoOpHash,
//! # };
@@ -365,19 +383,19 @@
//! # }
//! # use rand_core::{OsRng, RngCore};
//! # 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",
//! # ClientRegistrationStartParameters::default(),
//! # &mut client_rng,
//! # )?;
//! # let mut server_rng = OsRng;
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
//! # let (r3, export_key) = client_state.finish(r2, &mut client_rng)?;
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
//! # 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(
//! # b"password",
//! # &mut client_rng,
//! # b"password",
//! # ClientLoginStartParameters::default(),
//! # )?;
//! # use std::convert::TryFrom;
@@ -386,17 +404,22 @@
//! # &password_file_bytes[..],
//! # )?;
//! # let server_login_start_result =
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
//! # let client_login_finish_result = client_login_start_result.client_login_state.finish(
//! # server_login_start_result.credential_response,
//! # 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.state.finish(
//! # server_login_start_result.message,
//! # ClientLoginFinishParameters::default(),
//! # )?;
//! let server_login_finish_result = server_login_start_result.server_login_state.finish(client_login_finish_result.key_exchange)?;
//! assert_eq!(client_login_finish_result.session_secret, server_login_finish_result.session_secret);
//! let server_login_finish_result = server_login_start_result.state.finish(
//! client_login_finish_result.message,
//! )?;
//! assert_eq!(
//! client_login_finish_result.shared_secret,
//! server_login_finish_result.shared_secret,
//! );
//! # Ok::<(), ProtocolError>(())
//! ```
//! If the protocol completes successfully, then the server obtains a `server_shared_secret` which is guaranteed to
//! match `client_shared_secret`. Otherwise, on failure, the `finish` algorithm outputs the error `InvalidLoginError`.
//! If the protocol completes successfully, then the server obtains a `server_login_finish_result.shared_secret` which is guaranteed to
//! 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))]
@@ -443,8 +466,8 @@ mod tests;
// Exports
pub use crate::messages::{
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage,
RegisterSecondMessage, RegisterThirdMessage,
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegistrationResponse, RegistrationUpload,
};
pub use crate::opaque::{ClientLogin, ClientRegistration, ServerLogin, ServerRegistration};
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
pub struct RegisterFirstMessage<Grp> {
pub struct RegistrationRequest<Grp> {
/// blinded password information
pub(crate) alpha: Grp,
}
impl<Grp: Group> TryFrom<&[u8]> for RegisterFirstMessage<Grp> {
impl<Grp: Group> TryFrom<&[u8]> for RegistrationRequest<Grp> {
type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
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
pub fn to_bytes(&self) -> Vec<u8> {
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
/// registration attempt
pub struct RegisterSecondMessage<Grp> {
pub struct RegistrationResponse<Grp> {
/// The server's oprf output
pub(crate) beta: Grp,
/// Server's static public key
@@ -88,7 +88,7 @@ pub struct RegisterSecondMessage<Grp> {
pub(crate) ecf: EnvelopeCredentialsFormat,
}
impl<Grp> TryFrom<&[u8]> for RegisterSecondMessage<Grp>
impl<Grp> TryFrom<&[u8]> for RegistrationResponse<Grp>
where
Grp: Group,
{
@@ -116,7 +116,7 @@ where
}
}
impl<Grp> RegisterSecondMessage<Grp>
impl<Grp> RegistrationResponse<Grp>
where
Grp: Group,
{
@@ -196,7 +196,7 @@ where
/// The final message from the client, containing sealed cryptographic
/// identifiers
pub struct RegisterThirdMessage<KeyFormat: KeyPair, D: Hash> {
pub struct RegistrationUpload<KeyFormat: KeyPair, D: Hash> {
/// The "envelope" generated by the user, containing sealed
/// cryptographic identifiers
pub(crate) envelope: Envelope<D>,
@@ -204,7 +204,7 @@ pub struct RegisterThirdMessage<KeyFormat: KeyPair, D: Hash> {
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
KeyFormat: KeyPair,
D: Hash,
@@ -229,17 +229,17 @@ where
}
}
impl<KeyFormat, D> RegisterThirdMessage<KeyFormat, D>
impl<KeyFormat, D> RegistrationUpload<KeyFormat, D>
where
KeyFormat: KeyPair,
D: Hash,
{
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
let mut registration_upload: Vec<u8> = Vec::new();
registration_upload.extend_from_slice(&self.envelope.serialize());
registration_upload.extend_from_slice(&serialize(&self.client_s_pk.to_arr(), 2));
registration_upload
let mut message: Vec<u8> = Vec::new();
message.extend_from_slice(&self.envelope.serialize());
message.extend_from_slice(&serialize(&self.client_s_pk.to_arr(), 2));
message
}
/// Deserialization from bytes
@@ -259,20 +259,20 @@ where
}
/// 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
pub(crate) alpha: CS::Group,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeyFormat>>::KE1Message,
}
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> {
impl<CS: CipherSuite> TryFrom<&[u8]> for CredentialRequest<CS> {
type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
Self::deserialize(first_message_bytes)
}
}
impl<CS: CipherSuite> LoginFirstMessage<CS> {
impl<CS: CipherSuite> CredentialRequest<CS> {
/// byte representation for the login request
pub(crate) fn to_bytes(&self) -> Vec<u8> {
[&self.alpha.to_arr()[..], &self.ke1_message.to_bytes()].concat()
@@ -305,8 +305,8 @@ impl<CS: CipherSuite> LoginFirstMessage<CS> {
}
/// The answer sent by the server to the user, upon reception of the
/// login attempt.
pub struct LoginSecondMessage<CS: CipherSuite> {
/// login attempt
pub struct CredentialResponse<CS: CipherSuite> {
/// the server's oprf output
pub(crate) beta: CS::Group,
/// 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,
}
impl<CS: CipherSuite> LoginSecondMessage<CS> {
impl<CS: CipherSuite> CredentialResponse<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
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;
fn try_from(second_message_bytes: &[u8]) -> Result<Self, Self::Error> {
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
/// 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,
}
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginThirdMessage<CS> {
impl<CS: CipherSuite> TryFrom<&[u8]> for CredentialFinalization<CS> {
type Error = ProtocolError;
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
pub fn serialize(&self) -> Vec<u8> {
self.ke3_message.to_bytes()
+113 -92
View File
@@ -17,8 +17,8 @@ use crate::{
oprf,
serialization::{serialize, tokenize, CredentialType},
slow_hash::SlowHash,
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage,
RegisterSecondMessage, RegisterThirdMessage,
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegistrationResponse, RegistrationUpload,
};
use generic_array::{typenum::Unsigned, GenericArray};
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> {
/// 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;
/// }
/// 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>(())
/// ```
pub fn start<R: RngCore + CryptoRng>(
blinding_factor_rng: &mut R,
password: &[u8],
params: ClientRegistrationStartParameters,
blinding_factor_rng: &mut R,
#[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 {
ClientRegistrationStartParameters::WithIdentifiers(id_u, id_s) => (id_u, id_s),
};
@@ -144,17 +152,20 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
postprocess,
)?;
Ok((
RegisterFirstMessage::<CS::Group> { alpha },
Self { id_u, id_s, token },
))
Ok(ClientRegistrationStartResult {
message: RegistrationRequest::<CS::Group> { alpha },
state: Self { id_u, id_s, token },
})
}
}
type ClientRegistrationFinishResult<KeyFormat, D> = (
RegisterThirdMessage<KeyFormat, D>,
GenericArray<u8, ExportKeySize>,
);
/// Contains the fields that are returned by a client registration finish
pub struct ClientRegistrationFinishResult<KeyFormat: KeyPair, D: Hash> {
/// 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> {
/// "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 server_rng = OsRng;
/// 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 (register_m2, server_state) =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?;
/// let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// let server_registration_start_result =
/// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// 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>(())
/// ```
pub fn finish<R: CryptoRng + RngCore>(
self,
r2: RegisterSecondMessage<CS::Group>,
rng: &mut R,
r2: RegistrationResponse<CS::Group>,
) -> Result<ClientRegistrationFinishResult<CS::KeyFormat, CS::Hash>, ProtocolError> {
let client_static_keypair = CS::KeyFormat::generate_random(rng)?;
@@ -215,13 +226,13 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
let (envelope, export_key) =
Envelope::<CS::Hash>::seal(&password_derived_key, r2.ecf, credentials_map, rng)?;
Ok((
RegisterThirdMessage {
Ok(ClientRegistrationFinishResult {
message: RegistrationUpload {
envelope,
client_s_pk: client_static_keypair.public().clone(),
},
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
pub struct ServerRegistration<CS: CipherSuite> {
envelope: Option<Envelope<CS::Hash>>,
@@ -351,34 +370,34 @@ where
/// let mut client_rng = OsRng;
/// let mut server_rng = OsRng;
/// 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 (register_m2, server_state) =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?;
/// let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// let server_registration_start_result =
/// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # Ok::<(), ProtocolError>(())
/// ```
pub fn start<R: RngCore + CryptoRng>(
message: RegisterFirstMessage<CS::Group>,
server_s_pk: &<CS::KeyFormat as KeyPair>::Repr,
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
let oprf_key = CS::Group::random_scalar(rng);
// Compute beta = alpha^oprf_key
let beta = oprf::evaluate::<CS::Group>(message.alpha, &oprf_key);
Ok((
RegisterSecondMessage {
Ok(ServerRegistrationStartResult {
message: RegistrationResponse {
beta,
server_s_pk: server_s_pk.to_arr().to_vec(),
ecf: EnvelopeCredentialsFormat::default()?,
},
Self {
state: Self {
envelope: None,
client_s_pk: None,
oprf_key,
},
))
})
}
/// From the client's cryptographic identifiers, fully populates and
@@ -405,17 +424,17 @@ where
/// let mut client_rng = OsRng;
/// let mut server_rng = OsRng;
/// 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 (register_m2, server_state) =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?;
/// let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// let server_registration_start_result =
/// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// let mut client_rng = OsRng;
/// let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?;
/// let client_record = server_state.finish(register_m3)?;
/// let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// let client_record = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// # Ok::<(), ProtocolError>(())
/// ```
pub fn finish(
self,
message: RegisterThirdMessage<CS::KeyFormat, CS::Hash>,
message: RegistrationUpload<CS::KeyFormat, CS::Hash>,
) -> Result<Self, ProtocolError> {
Ok(Self {
envelope: Some(message.envelope),
@@ -511,9 +530,9 @@ impl Default for ClientLoginStartParameters {
/// Contains the fields that are returned by a client login start
pub struct ClientLoginStartResult<CS: CipherSuite> {
/// 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
pub client_login_state: ClientLogin<CS>,
pub state: ClientLogin<CS>,
}
/// 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
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
pub key_exchange: LoginThirdMessage<CS>,
pub message: CredentialFinalization<CS>,
/// The shared session secret
pub session_secret: Vec<u8>,
pub shared_secret: Vec<u8>,
/// The client-side export key
pub export_key: GenericArray<u8, ExportKeySize>,
/// The server's static public key
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>>,
/// 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> {
@@ -568,12 +587,12 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
/// }
/// 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>(())
/// ```
pub fn start<R: RngCore + CryptoRng>(
password: &[u8],
rng: &mut R,
password: &[u8],
params: ClientLoginStartParameters,
#[cfg(test)] postprocess: fn(<CS::Group as Group>::Scalar) -> <CS::Group as Group>::Scalar,
) -> Result<ClientLoginStartResult<CS>, ProtocolError> {
@@ -594,11 +613,11 @@ impl<CS: CipherSuite> ClientLogin<CS> {
let (ke1_state, ke1_message) =
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 {
credential_request: l1,
client_login_state: Self {
message: l1,
state: Self {
id_u,
id_s,
token,
@@ -632,19 +651,19 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// }
/// let mut client_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 (register_m2, server_state) = ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?;
/// # let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?;
/// # let p_file = server_state.finish(register_m3)?;
/// let client_login_start_result = ClientLogin::<Default>::start(b"hunter2", &mut client_rng, 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 client_login_finish_result = client_login_start_result.client_login_state.finish(server_login_start_result.credential_response, ClientLoginFinishParameters::default())?;
/// # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// # let p_file = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"hunter2", ClientLoginStartParameters::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.state.finish(server_login_start_result.message, ClientLoginFinishParameters::default())?;
/// # Ok::<(), ProtocolError>(())
/// ```
pub fn finish(
self,
l2: LoginSecondMessage<CS>,
l2: CredentialResponse<CS>,
params: ClientLoginFinishParameters,
) -> Result<ClientLoginFinishResult<CS>, ProtocolError> {
let (info, e_info) = match params {
@@ -683,7 +702,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
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(
l2_bytes,
l2.ke2_message,
@@ -699,8 +718,8 @@ impl<CS: CipherSuite> ClientLogin<CS> {
Ok(ClientLoginFinishResult {
plain_info,
confidential_info,
key_exchange: LoginThirdMessage { ke3_message },
session_secret,
message: CredentialFinalization { ke3_message },
shared_secret,
export_key: opened_envelope.export_key,
server_s_pk: server_s_pk.to_arr().to_vec(),
id_s: ret_id_s,
@@ -744,26 +763,28 @@ impl Default for ServerLoginStartParameters {
/// Contains the fields that are returned by a server login start
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
pub credential_response: LoginSecondMessage<CS>,
pub message: CredentialResponse<CS>,
/// 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
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
pub struct ServerLoginFinishResult {
/// The shared session secret between client and server
pub shared_secret: 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>,
/// The shared session secret between client and server
pub session_secret: Vec<u8>,
}
impl ServerLoginFinishResult {}
impl<CS: CipherSuite> ServerLogin<CS> {
/// byte representation for the server's login state
pub fn to_bytes(&self) -> Vec<u8> {
@@ -796,20 +817,20 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// let mut client_rng = OsRng;
/// let mut server_rng = OsRng;
/// 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 (register_m2, server_state) =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?;
/// # let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?;
/// # let p_file = server_state.finish(register_m3)?;
/// let client_login_start_result = ClientLogin::<Default>::start(b"hunter2", &mut client_rng, 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 client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// # let server_registration_start_result =
/// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// # let p_file = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"hunter2", ClientLoginStartParameters::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>(())
/// ```
pub fn start<R: RngCore + CryptoRng>(
rng: &mut R,
password_file: ServerRegistration<CS>,
server_s_sk: &<CS::KeyFormat as KeyPair>::Repr,
l1: LoginFirstMessage<CS>,
rng: &mut R,
l1: CredentialRequest<CS>,
params: ServerLoginStartParameters,
) -> Result<ServerLoginStartResult<CS>, ProtocolError> {
let client_s_pk = password_file
@@ -853,7 +874,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
e_info,
)?;
let l2 = LoginSecondMessage {
let l2 = CredentialResponse {
beta,
envelope,
ke2_message,
@@ -861,8 +882,8 @@ impl<CS: CipherSuite> ServerLogin<CS> {
Ok(ServerLoginStartResult {
plain_info,
credential_response: l2,
server_login_state: Self {
message: l2,
state: Self {
_cs: PhantomData,
ke2_state,
},
@@ -896,22 +917,22 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// let mut client_rng = OsRng;
/// let mut server_rng = OsRng;
/// 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 (register_m2, server_state) =
/// ServerRegistration::<Default>::start(register_m1, server_kp.public(), &mut server_rng)?;
/// # let (register_m3, _export_key) = client_state.finish(register_m2, &mut client_rng)?;
/// # let p_file = server_state.finish(register_m3)?;
/// let client_login_start_result = ClientLogin::<Default>::start(b"hunter2", &mut client_rng, 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 client_login_finish_result = client_login_start_result.client_login_state.finish(server_login_start_result.credential_response, ClientLoginFinishParameters::default())?;
/// let mut server_transport = server_login_start_result.server_login_state.finish(client_login_finish_result.key_exchange)?;
/// # let client_registration_start_result = ClientRegistration::<Default>::start(&mut client_rng, b"hunter2", ClientRegistrationStartParameters::default())?;
/// # let server_registration_start_result =
/// ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
/// # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message)?;
/// # let p_file = server_registration_start_result.state.finish(client_registration_finish_result.message)?;
/// let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"hunter2", ClientLoginStartParameters::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.state.finish(server_login_start_result.message, ClientLoginFinishParameters::default())?;
/// let mut server_transport = server_login_start_result.state.finish(client_login_finish_result.message)?;
/// # Ok::<(), ProtocolError>(())
/// ```
pub fn finish(
&self,
message: LoginThirdMessage<CS>,
message: CredentialFinalization<CS>,
) -> 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(
message.ke3_message,
&self.ke2_state,
@@ -926,7 +947,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
Ok(ServerLoginFinishResult {
plain_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(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();
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(&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();
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_bytes[..]);
let r3 = RegisterThirdMessage::<X25519KeyPair, sha2::Sha256>::deserialize(&input[..]).unwrap();
let r3 = RegistrationUpload::<X25519KeyPair, sha2::Sha256>::deserialize(&input[..]).unwrap();
let r3_bytes = r3.serialize();
assert_eq!(input, r3_bytes);
}
@@ -205,7 +205,7 @@ fn login_first_message_roundtrip() {
input.extend_from_slice(&alpha_bytes);
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();
assert_eq!(input, l1_bytes);
}
@@ -254,7 +254,7 @@ fn login_second_message_roundtrip() {
input.extend_from_slice(&envelope.serialize());
input.extend_from_slice(&ke2m[..]);
let l2 = LoginSecondMessage::<Default>::deserialize(&input).unwrap();
let l2 = CredentialResponse::<Default>::deserialize(&input).unwrap();
let l2_bytes = l2.serialize();
assert_eq!(input, l2_bytes);
}
@@ -276,7 +276,7 @@ fn login_third_message_roundtrip() {
]
.concat();
let l3 = LoginThirdMessage::<Default>::deserialize(&input).unwrap();
let l3 = CredentialFinalization::<Default>::deserialize(&input).unwrap();
let l3_bytes = l3.serialize();
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]
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]
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]
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]
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]
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]
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]
+183 -128
View File
@@ -55,12 +55,12 @@ pub struct TestVectorParameters {
pub einfo2: Vec<u8>,
pub info3: Vec<u8>,
pub einfo3: Vec<u8>,
pub r1: Vec<u8>,
pub r2: Vec<u8>,
pub r3: Vec<u8>,
pub l1: Vec<u8>,
pub l2: Vec<u8>,
pub l3: Vec<u8>,
pub registration_request: Vec<u8>,
pub registration_response: Vec<u8>,
pub message: Vec<u8>,
pub credential_request: Vec<u8>,
pub credential_response: Vec<u8>,
pub key_exchange: Vec<u8>,
client_registration_state: Vec<u8>,
server_registration_state: Vec<u8>,
client_login_state: Vec<u8>,
@@ -93,12 +93,12 @@ static TEST_VECTOR: &str = r#"
"einfo2": "65696e666f32",
"info3": "696e666f33",
"einfo3": "65696e666f33",
"r1": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b365957",
"r2": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa80020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e01010103",
"r3": "abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed8900205320b55752ad2061c1804050f8a225a4ab1184bc17d8fa6b3c86470c33d9ce42",
"l1": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b3659571a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c70005696e666f3177fc3fefb8178ae08461756b54364c4f2d1363d5ce3187af128a3f84a6c5722a",
"l2": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa8abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed89606034b9be54759ea5802a2dd71e4413e98d52c46e60f2d0868642ad9e6a9b460005696e666f325a314dc389c12bf041b14e131fadebcc98e0fc33d3cd996ad9392c7ae6bff468000665696e666f32661aa1d3e579032df30a78312d38a4c3d8d8a0f1b9bb7bbdbff040e0881a248e",
"l3": "0005696e666f33000665696e666f3317090781af5a220941ddd6db7d4f2af33d9b316a48aee163647131970bae50ba",
"registration_request": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b365957",
"registration_response": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa80020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e01010103",
"message": "abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed8900205320b55752ad2061c1804050f8a225a4ab1184bc17d8fa6b3c86470c33d9ce42",
"credential_request": "0020c4ad91692b704470e0613850b9bfcc5b265d43f9ba03dd6ff028f0fb6b3659571a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c70005696e666f3177fc3fefb8178ae08461756b54364c4f2d1363d5ce3187af128a3f84a6c5722a",
"credential_response": "00205cbfd7b74c7fe6088f8117e7e63000675762920b75e0f4630ed67d4d960c7aa8abb706633ac7092e2aa63dedd4b456d7d99870f099c4f2c51ba75da0f20db8e80023e76da9b9fbf400fea214ecdab24966e4d3fea9d0c3d5d672597e1e702eb30547495ada0023030020b8c5defc933aaf3640d13f217c392e06fe5fd41fae8571204fcbb804a566cd2e00204e0e5754fbbd48efcdab43cee37f6455f357f3edc54316cb69da8f8e92f5ed89606034b9be54759ea5802a2dd71e4413e98d52c46e60f2d0868642ad9e6a9b460005696e666f325a314dc389c12bf041b14e131fadebcc98e0fc33d3cd996ad9392c7ae6bff468000665696e666f32661aa1d3e579032df30a78312d38a4c3d8d8a0f1b9bb7bbdbff040e0881a248e",
"key_exchange": "0005696e666f33000665696e666f3317090781af5a220941ddd6db7d4f2af33d9b316a48aee163647131970bae50ba",
"client_registration_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130070617373776f7264",
"client_login_state": "00036964550003696453c0accb2010d728cfce827d4cb3769000c8b42ac341db8ba196fbe75809d9130048b452f6d0b28387cfa98245bda9230b6df215ed5b820bffb8511ec6802d80751a92d39b2f9acdbef96dcc586b35ae056a085ede41b05f9f81801f69558d44c7288b735853d9e1d8ab699b7c4aef54680f036c56140dc0a4991f6d02a95babc970617373776f7264",
"server_registration_state": "7f1d2a048a7aad9d1cf2b96473e3adbb1e0626eafe0abdfd09f1f700beda9d0f",
@@ -138,12 +138,12 @@ fn populate_test_vectors(values: &Value) -> TestVectorParameters {
einfo2: decode(&values, "einfo2").unwrap(),
info3: decode(&values, "info3").unwrap(),
einfo3: decode(&values, "einfo3").unwrap(),
r1: decode(&values, "r1").unwrap(),
r2: decode(&values, "r2").unwrap(),
r3: decode(&values, "r3").unwrap(),
l1: decode(&values, "l1").unwrap(),
l2: decode(&values, "l2").unwrap(),
l3: decode(&values, "l3").unwrap(),
registration_request: decode(&values, "registration_request").unwrap(),
registration_response: decode(&values, "registration_response").unwrap(),
message: decode(&values, "message").unwrap(),
credential_request: decode(&values, "credential_request").unwrap(),
credential_response: decode(&values, "credential_response").unwrap(),
key_exchange: decode(&values, "key_exchange").unwrap(),
client_registration_state: decode(&values, "client_registration_state").unwrap(),
client_login_state: decode(&values, "client_login_state").unwrap(),
server_registration_state: decode(&values, "server_registration_state").unwrap(),
@@ -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!("\"info3\": \"{}\",\n", hex::encode(&p.info3)).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(format!("\"r2\": \"{}\",\n", hex::encode(&p.r2)).as_str());
s.push_str(format!("\"r3\": \"{}\",\n", hex::encode(&p.r3)).as_str());
s.push_str(format!("\"l1\": \"{}\",\n", hex::encode(&p.l1)).as_str());
s.push_str(format!("\"l2\": \"{}\",\n", hex::encode(&p.l2)).as_str());
s.push_str(format!("\"l3\": \"{}\",\n", hex::encode(&p.l3)).as_str());
s.push_str(
format!(
"\"registration_request\": \"{}\",\n",
hex::encode(&p.registration_request)
)
.as_str(),
);
s.push_str(
format!(
"\"registration_response\": \"{}\",\n",
hex::encode(&p.registration_response)
)
.as_str(),
);
s.push_str(format!("\"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(
format!(
"\"client_registration_state\": \"{}\",\n",
@@ -277,36 +301,57 @@ where
let einfo3 = b"einfo3";
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,
ClientRegistrationStartParameters::WithIdentifiers(id_u.to_vec(), id_s.to_vec()),
&mut blinding_factor_registration_rng,
std::convert::identity,
)
.unwrap();
let r1_bytes = r1.serialize().to_vec();
let registration_request_bytes = client_registration_start_result
.message
.serialize()
.to_vec();
let blinding_factor_bytes =
CS::Group::scalar_as_bytes(&client_registration.token.blind).clone();
let client_registration_state = client_registration.to_bytes().to_vec();
CS::Group::scalar_as_bytes(&client_registration_start_result.state.token.blind).clone();
let client_registration_state = client_registration_start_result.state.to_bytes().to_vec();
let mut oprf_key_rng = CycleRng::new(oprf_key_raw.to_vec());
let (r2, server_registration) =
ServerRegistration::<CS>::start(r1, server_s_kp.public(), &mut oprf_key_rng).unwrap();
let r2_bytes = r2.serialize().to_vec();
let oprf_key_bytes = CS::Group::scalar_as_bytes(&server_registration.oprf_key).clone();
let server_registration_state = server_registration.to_bytes().to_vec();
let server_registration_start_result = ServerRegistration::<CS>::start(
&mut oprf_key_rng,
client_registration_start_result.message,
server_s_kp.public(),
)
.unwrap();
let registration_response_bytes = server_registration_start_result
.message
.serialize()
.to_vec();
let oprf_key_bytes =
CS::Group::scalar_as_bytes(&server_registration_start_result.state.oprf_key).clone();
let server_registration_state = server_registration_start_result.state.to_bytes().to_vec();
let mut client_s_sk_and_nonce: Vec<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(&envelope_nonce);
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
let (r3, export_key_registration) = client_registration
.finish(r2, &mut finish_registration_rng)
let client_registration_finish_result = client_registration_start_result
.state
.finish(
&mut finish_registration_rng,
server_registration_start_result.message,
)
.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 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 client_login_start_result = ClientLogin::<CS>::start(
password,
&mut client_login_start_rng,
password,
ClientLoginStartParameters::WithInfoAndIdentifiers(
info1.to_vec(),
id_u.to_vec(),
@@ -326,41 +371,29 @@ where
std::convert::identity,
)
.unwrap();
let l1_bytes = client_login_start_result
.credential_request
.serialize()
.to_vec();
let client_login_state = client_login_start_result
.client_login_state
.to_bytes()
.to_vec();
let credential_request_bytes = client_login_start_result.message.serialize().to_vec();
let client_login_state = client_login_start_result.state.to_bytes().to_vec();
let mut server_e_sk_rng = CycleRng::new(server_e_kp.private().to_arr().to_vec());
let server_login_start_result = ServerLogin::<CS>::start(
&mut server_e_sk_rng,
password_file,
server_s_kp.private(),
client_login_start_result.credential_request,
&mut server_e_sk_rng,
client_login_start_result.message,
ServerLoginStartParameters::WithInfo(info2.to_vec(), einfo2.to_vec()),
)
.unwrap();
let l2_bytes = server_login_start_result
.credential_response
.serialize()
.to_vec();
let server_login_state = server_login_start_result
.server_login_state
.to_bytes()
.to_vec();
let credential_response_bytes = server_login_start_result.message.serialize().to_vec();
let server_login_state = server_login_start_result.state.to_bytes().to_vec();
let client_login_finish_result = client_login_start_result
.client_login_state
.state
.finish(
server_login_start_result.credential_response,
server_login_start_result.message,
ClientLoginFinishParameters::WithInfo(info3.to_vec(), einfo3.to_vec()),
)
.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 {
client_s_pk: client_s_kp.public().to_arr().to_vec(),
@@ -384,19 +417,19 @@ where
einfo2: einfo2.to_vec(),
info3: info3.to_vec(),
einfo3: einfo3.to_vec(),
r1: r1_bytes,
r2: r2_bytes,
r3: r3_bytes,
l1: l1_bytes,
l2: l2_bytes,
l3: l3_bytes,
registration_request: registration_request_bytes,
registration_response: registration_response_bytes,
message: message_bytes,
credential_request: credential_request_bytes,
credential_response: credential_response_bytes,
key_exchange: key_exchange_bytes,
password_file: password_file_bytes,
client_registration_state,
server_registration_state,
client_login_state,
server_login_state,
shared_secret: client_login_finish_result.session_secret,
export_key: export_key_registration.to_vec(),
shared_secret: client_login_finish_result.shared_secret,
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]
fn test_r1() -> Result<(), ProtocolError> {
fn test_registration_request() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let mut rng = OsRng;
let (r1, client_registration) = ClientRegistration::<X255193dhNoSlowHash>::start(
let client_registration_start_result = ClientRegistration::<X255193dhNoSlowHash>::start(
&mut rng,
&parameters.password,
ClientRegistrationStartParameters::WithIdentifiers(parameters.id_u, parameters.id_s),
&mut rng,
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!(
hex::encode(&parameters.client_registration_state),
hex::encode(client_registration.to_bytes())
hex::encode(client_registration_start_result.state.to_bytes())
);
Ok(())
}
#[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 mut oprf_key_rng = CycleRng::new(parameters.oprf_key);
let (r2, server_registration) = ServerRegistration::<X255193dhNoSlowHash>::start(
RegisterFirstMessage::deserialize(&parameters.r1[..]).unwrap(),
&Key::try_from(&parameters.server_s_pk[..]).unwrap(),
let server_registration_start_result = ServerRegistration::<X255193dhNoSlowHash>::start(
&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!(
hex::encode(&parameters.server_registration_state),
hex::encode(server_registration.to_bytes())
hex::encode(server_registration_start_result.state.to_bytes())
);
Ok(())
}
#[test]
fn test_r3() -> Result<(), ProtocolError> {
fn test_message() -> Result<(), ProtocolError> {
let parameters = populate_test_vectors(&serde_json::from_str(TEST_VECTOR).unwrap());
let client_s_sk_and_nonce: Vec<u8> =
[parameters.client_s_sk, parameters.envelope_nonce].concat();
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
let (r3, export_key_registration) = ClientRegistration::<X255193dhNoSlowHash>::try_from(
let result = ClientRegistration::<X255193dhNoSlowHash>::try_from(
&parameters.client_registration_state[..],
)?
.finish(
RegisterSecondMessage::deserialize(&parameters.r2[..]).unwrap(),
&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!(
hex::encode(parameters.export_key),
hex::encode(export_key_registration.to_vec())
hex::encode(result.export_key.to_vec())
);
Ok(())
@@ -478,7 +521,8 @@ fn test_password_file() -> Result<(), ProtocolError> {
&parameters.server_registration_state[..],
)?;
let password_file = server_registration
.finish(RegisterThirdMessage::deserialize(&parameters.r3[..]).unwrap())?;
.finish(RegistrationUpload::deserialize(&parameters.message[..]).unwrap())?;
assert_eq!(
hex::encode(parameters.password_file),
hex::encode(password_file.to_bytes())
@@ -487,7 +531,7 @@ fn test_password_file() -> Result<(), ProtocolError> {
}
#[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 client_login_start = [
@@ -498,8 +542,8 @@ fn test_l1() -> Result<(), ProtocolError> {
.concat();
let mut client_login_start_rng = CycleRng::new(client_login_start);
let client_login_start_result = ClientLogin::<X255193dhNoSlowHash>::start(
&parameters.password,
&mut client_login_start_rng,
&parameters.password,
ClientLoginStartParameters::WithInfoAndIdentifiers(
parameters.info1,
parameters.id_u,
@@ -508,26 +552,27 @@ fn test_l1() -> Result<(), ProtocolError> {
postprocess_blinding_factor::<<X255193dhNoSlowHash as CipherSuite>::Group>,
)?;
assert_eq!(
hex::encode(&parameters.l1),
hex::encode(client_login_start_result.credential_request.serialize())
hex::encode(&parameters.credential_request),
hex::encode(client_login_start_result.message.serialize())
);
assert_eq!(
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(())
}
#[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 mut server_e_sk_rng = CycleRng::new(parameters.server_e_sk);
let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start(
&mut server_e_sk_rng,
ServerRegistration::try_from(&parameters.password_file[..]).unwrap(),
&Key::try_from(&parameters.server_s_sk[..]).unwrap(),
LoginFirstMessage::<X255193dhNoSlowHash>::deserialize(&parameters.l1[..]).unwrap(),
&mut server_e_sk_rng,
CredentialRequest::<X255193dhNoSlowHash>::deserialize(&parameters.credential_request[..])
.unwrap(),
ServerLoginStartParameters::WithInfo(parameters.info2.to_vec(), parameters.einfo2.to_vec()),
)?;
assert_eq!(
@@ -539,28 +584,33 @@ fn test_l2() -> Result<(), ProtocolError> {
hex::encode(server_login_start_result.client_s_pk),
);
assert_eq!(
hex::encode(&parameters.l2),
hex::encode(server_login_start_result.credential_response.serialize())
hex::encode(&parameters.credential_response),
hex::encode(server_login_start_result.message.serialize())
);
assert_eq!(
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(())
}
#[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 client_login_finish_result =
ClientLogin::<X255193dhNoSlowHash>::try_from(&parameters.client_login_state[..])?.finish(
LoginSecondMessage::<X255193dhNoSlowHash>::deserialize(&parameters.l2[..]).unwrap(),
ClientLoginFinishParameters::WithInfo(
parameters.info3.to_vec(),
parameters.einfo3.to_vec(),
),
)?;
ClientLogin::<X255193dhNoSlowHash>::try_from(&parameters.client_login_state[..])
.unwrap()
.finish(
CredentialResponse::<X255193dhNoSlowHash>::deserialize(
&parameters.credential_response[..],
)?,
ClientLoginFinishParameters::WithInfo(
parameters.info3.to_vec(),
parameters.einfo3.to_vec(),
),
)?;
assert_eq!(
hex::encode(&parameters.info2),
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!(
hex::encode(&parameters.shared_secret),
hex::encode(&client_login_finish_result.session_secret)
hex::encode(&client_login_finish_result.shared_secret)
);
assert_eq!(
hex::encode(&parameters.l3),
hex::encode(client_login_finish_result.key_exchange.to_bytes())
hex::encode(&parameters.key_exchange),
hex::encode(client_login_finish_result.message.to_bytes())
);
assert_eq!(
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 server_login_result =
ServerLogin::<X255193dhNoSlowHash>::try_from(&parameters.server_login_state[..])?
.finish(LoginThirdMessage::try_from(&parameters.l3[..])?)?;
ServerLogin::<X255193dhNoSlowHash>::try_from(&parameters.server_login_state[..])?.finish(
CredentialFinalization::try_from(&parameters.key_exchange[..])?,
)?;
assert_eq!(
hex::encode(parameters.info3),
hex::encode(server_login_result.plain_info)
@@ -607,7 +659,7 @@ fn test_server_login_finish() -> Result<(), ProtocolError> {
);
assert_eq!(
hex::encode(parameters.shared_secret),
hex::encode(server_login_result.session_secret)
hex::encode(server_login_result.shared_secret)
);
Ok(())
@@ -620,51 +672,54 @@ fn test_complete_flow(
let mut client_rng = OsRng;
let mut server_rng = OsRng;
let server_kp = X255193dhNoSlowHash::generate_random_keypair(&mut server_rng)?;
let (register_m1, client_state) = ClientRegistration::<X255193dhNoSlowHash>::start(
let client_registration_start_result = ClientRegistration::<X255193dhNoSlowHash>::start(
&mut client_rng,
registration_password,
ClientRegistrationStartParameters::default(),
&mut client_rng,
std::convert::identity,
)?;
let (register_m2, server_state) = ServerRegistration::<X255193dhNoSlowHash>::start(
register_m1,
server_kp.public(),
let server_registration_start_result = ServerRegistration::<X255193dhNoSlowHash>::start(
&mut server_rng,
client_registration_start_result.message,
server_kp.public(),
)?;
let (register_m3, registration_export_key) =
client_state.finish(register_m2, &mut client_rng)?;
let p_file = server_state.finish(register_m3)?;
let client_registration_finish_result = client_registration_start_result
.state
.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(
login_password,
&mut client_rng,
login_password,
ClientLoginStartParameters::default(),
std::convert::identity,
)?;
let server_login_start_result = ServerLogin::<X255193dhNoSlowHash>::start(
&mut server_rng,
p_file,
&server_kp.private(),
client_login_start_result.credential_request,
&mut server_rng,
client_login_start_result.message,
ServerLoginStartParameters::default(),
)?;
let client_login_result = client_login_start_result.client_login_state.finish(
server_login_start_result.credential_response,
let client_login_result = client_login_start_result.state.finish(
server_login_start_result.message,
ClientLoginFinishParameters::default(),
);
if hex::encode(registration_password) == hex::encode(login_password) {
let client_login_finish_result = client_login_result?;
let server_login_finish_result = server_login_start_result
.server_login_state
.finish(client_login_finish_result.key_exchange)?;
.state
.finish(client_login_finish_result.message)?;
assert_eq!(
hex::encode(server_login_finish_result.session_secret),
hex::encode(client_login_finish_result.session_secret)
hex::encode(server_login_finish_result.shared_secret),
hex::encode(client_login_finish_result.shared_secret)
);
assert_eq!(
hex::encode(registration_export_key),
hex::encode(client_registration_finish_result.export_key),
hex::encode(client_login_finish_result.export_key)
);
} else {