Adding documentation for advanced usage + optional parameters (#110)
This commit is contained in:
+333
-13
@@ -65,7 +65,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Client Registration Start
|
//! ### Client Registration Start
|
||||||
//! In the first step of registration, the client chooses as input a registration password. The client runs [ClientRegistration::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
|
//! to produce a [ClientRegistrationStartResult], which consists 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.
|
//! a [ClientRegistration] which must be persisted on the client for the final step of client registration.
|
||||||
//! ```
|
//! ```
|
||||||
//! # use opaque_ke::{
|
//! # use opaque_ke::{
|
||||||
@@ -96,8 +96,8 @@
|
|||||||
//! ### Server Registration Start
|
//! ### Server Registration Start
|
||||||
//! In the second step of registration, the server takes as input the instance of [RegistrationRequest] from the client, and
|
//! 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's public key `server_kp.public()`.
|
||||||
//! The server runs [ServerRegistration::start] to produce an output consisting of
|
//! The server runs [ServerRegistration::start] to produce an a [ServerRegistrationStartResult], which consists of
|
||||||
//! a [RegistrationResponse] to be returned to the client, and
|
//! 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.
|
//! a [ServerRegistration] which must be persisted on the server for the final step of server registration.
|
||||||
//! ```
|
//! ```
|
||||||
//! # use opaque_ke::{
|
//! # use opaque_ke::{
|
||||||
@@ -136,8 +136,8 @@
|
|||||||
//! In the third step of registration, the client takes as input
|
//! In the third step of registration, the client takes as input
|
||||||
//! a [RegistrationResponse] from the server, and
|
//! a [RegistrationResponse] from the server, and
|
||||||
//! a [ClientRegistration] from the first step of registration.
|
//! a [ClientRegistration] from the first step of registration.
|
||||||
//! The client runs [ClientRegistration::finish] to produce an output consisting of a [RegistrationUpload]
|
//! The client runs [ClientRegistration::finish] to produce a [ClientRegistrationFinishResult], which consists of a [RegistrationUpload]
|
||||||
//! to be sent to the server.
|
//! to be sent to the server and an `export_key` field which can be used optionally as described in the [Export Key](#export-key) section.
|
||||||
//! ```
|
//! ```
|
||||||
//! # use opaque_ke::{
|
//! # use opaque_ke::{
|
||||||
//! # errors::ProtocolError,
|
//! # errors::ProtocolError,
|
||||||
@@ -347,13 +347,9 @@
|
|||||||
//! # let server_login_start_result =
|
//! # let server_login_start_result =
|
||||||
//! # ServerLogin::start(&mut server_rng, password_file, &server_kp.private(), client_login_start_result.message, 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.state.finish(
|
//! let client_login_finish_result = client_login_start_result.state.finish(
|
||||||
//! server_login_start_result.message,
|
//! server_login_start_result.message,
|
||||||
//! ClientLoginFinishParameters::default(),
|
//! ClientLoginFinishParameters::default(),
|
||||||
//! )?;
|
//! )?;
|
||||||
//! assert_eq!(
|
|
||||||
//! client_registration_finish_result.export_key,
|
|
||||||
//! client_login_finish_result.export_key,
|
|
||||||
//! );
|
|
||||||
//! # Ok::<(), ProtocolError>(())
|
//! # Ok::<(), ProtocolError>(())
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
@@ -404,8 +400,9 @@
|
|||||||
//! # ClientLoginFinishParameters::default(),
|
//! # ClientLoginFinishParameters::default(),
|
||||||
//! # )?;
|
//! # )?;
|
||||||
//! let server_login_finish_result = server_login_start_result.state.finish(
|
//! let server_login_finish_result = server_login_start_result.state.finish(
|
||||||
//! client_login_finish_result.message,
|
//! client_login_finish_result.message,
|
||||||
//! )?;
|
//! )?;
|
||||||
|
//!
|
||||||
//! assert_eq!(
|
//! assert_eq!(
|
||||||
//! client_login_finish_result.shared_secret,
|
//! client_login_finish_result.shared_secret,
|
||||||
//! server_login_finish_result.shared_secret,
|
//! server_login_finish_result.shared_secret,
|
||||||
@@ -413,7 +410,330 @@
|
|||||||
//! # Ok::<(), ProtocolError>(())
|
//! # Ok::<(), ProtocolError>(())
|
||||||
//! ```
|
//! ```
|
||||||
//! If the protocol completes successfully, then the server obtains a `server_login_finish_result.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_login_finish_result.shared_secret`. Otherwise, on failure, the [ServerLogin::finish] algorithm outputs the error [InvalidLoginError](errors::PakeError::InvalidLoginError).
|
//! match `client_login_finish_result.shared_secret` (see the [Shared Secret](#shared-secret) section).
|
||||||
|
//! Otherwise, on failure, the [ServerLogin::finish] algorithm outputs the error [InvalidLoginError](errors::PakeError::InvalidLoginError).
|
||||||
|
//!
|
||||||
|
//! # Advanced Usage
|
||||||
|
//!
|
||||||
|
//! This implementation offers support for several optional features of OPAQUE, described below. They are not critical to the
|
||||||
|
//! execution of the main protocol, but can provide additional security benefits which can be suitable for various applications that rely on
|
||||||
|
//! OPAQUE for authentication.
|
||||||
|
//!
|
||||||
|
//! ## Shared Secret
|
||||||
|
//!
|
||||||
|
//! Upon a successful completion of the OPAQUE protocol (the client runs login with the same password used during registration),
|
||||||
|
//! the client and server have access to a shared secret, which is a pseudorandomly distributed 32-byte string which only the client
|
||||||
|
//! and server know. Multiple login runs using the same password for the same client will produce different shared secrets, distributed
|
||||||
|
//! as uniformly random strings. Thus, the shared secret can be used as a session secret for a secure channel between the client and server.
|
||||||
|
//!
|
||||||
|
//! The shared secret can be accessed from the `shared_secret` field of [ClientLoginFinishResult] and [ServerLoginFinishResult]. See
|
||||||
|
//! the combination of [Client Login Finish](#client-login-finish) and [Server Login Finish](#server-login-finish) for example usage.
|
||||||
|
//!
|
||||||
|
//! ## Checking Server Consistency
|
||||||
|
//!
|
||||||
|
//! A [ClientLoginFinishResult] contains the `server_s_pk` field, which is represents the static public key of the server that is established
|
||||||
|
//! during the setup phase. This can be used by the client to verify the authenticity of the server it engages with during the login phase. In particular,
|
||||||
|
//! the client can check that the static public key of the server supplied during registration matches this field during login.
|
||||||
|
//! ```
|
||||||
|
//! # use opaque_ke::{
|
||||||
|
//! # errors::ProtocolError,
|
||||||
|
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization,
|
||||||
|
//! # keypair::{KeyPair, X25519KeyPair},
|
||||||
|
//! # slow_hash::NoOpHash,
|
||||||
|
//! # };
|
||||||
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
|
//! # type Hash = sha2::Sha256;
|
||||||
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
|
//! # }
|
||||||
|
//! # use rand_core::{OsRng, RngCore};
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # )?;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! // During setup, server generates its static keypair
|
||||||
|
//! let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
||||||
|
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
|
||||||
|
//!
|
||||||
|
//! // During setup or registration, the server transmits its static public key to the client
|
||||||
|
//! let server_s_pk = server_kp.public(); // obtained from the server
|
||||||
|
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
|
||||||
|
//! # 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(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # ClientLoginStartParameters::default(),
|
||||||
|
//! # )?;
|
||||||
|
//! # use std::convert::TryFrom;
|
||||||
|
//! # let password_file =
|
||||||
|
//! # ServerRegistration::<Default>::try_from(
|
||||||
|
//! # &password_file_bytes[..],
|
||||||
|
//! # )?;
|
||||||
|
//! # let server_login_start_result =
|
||||||
|
//! # ServerLogin::start(&mut server_rng, password_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default())?;
|
||||||
|
//!
|
||||||
|
//! // And then later, during login...
|
||||||
|
//! let client_login_finish_result = client_login_start_result.state.finish(
|
||||||
|
//! server_login_start_result.message,
|
||||||
|
//! ClientLoginFinishParameters::default(),
|
||||||
|
//! )?;
|
||||||
|
//!
|
||||||
|
//! // Check that the server's static public key matches what was obtained during
|
||||||
|
//! // setup or registration
|
||||||
|
//! assert_eq!(
|
||||||
|
//! &client_login_finish_result.server_s_pk,
|
||||||
|
//! server_s_pk,
|
||||||
|
//! );
|
||||||
|
//! # Ok::<(), ProtocolError>(())
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Note that without this check over the consistency of the server's static public key, a malicious actor could impersonate the registration server if it were able to copy the password
|
||||||
|
//! file output during registration! Therefore, it is recommended to perform the following check in the application layer if the client can obtain a copy of the server's static
|
||||||
|
//! public key beforehand.
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! ## Export Key
|
||||||
|
//!
|
||||||
|
//! The export key is a pseudorandomly distributed 32-byte string output by both the
|
||||||
|
//! [Client Registration Finish](#client-registration-finish) and [Client Login Finish](#client-login-finish) steps.
|
||||||
|
//! The same export key string will be output by both functions only if the exact same password is passed to [ClientRegistration::start] and [ClientLogin::start].
|
||||||
|
//!
|
||||||
|
//! The export key retains as much secrecy as the password itself, and is similarly derived through an evaluation of the slow hashing function. Hence, only the parties which
|
||||||
|
//! know the password the client uses during registration and login can recover this secret, as it is never exposed to the server. As a result, the export key
|
||||||
|
//! can be used (separately from the OPAQUE protocol) to provide confidentiality and integrity to other data which only the client should be able to process.
|
||||||
|
//! For instance, if the server is expected to maintain any client-side secrets which require a password to access, then this export key can be used to encrypt
|
||||||
|
//! these secrets so that they remain hidden from the server.
|
||||||
|
//!
|
||||||
|
//! You can access the export key from the `export_key` field of [ClientRegistrationFinishResult] and [ClientLoginFinishResult].
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use opaque_ke::{
|
||||||
|
//! # errors::ProtocolError,
|
||||||
|
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization,
|
||||||
|
//! # keypair::{KeyPair, X25519KeyPair},
|
||||||
|
//! # slow_hash::NoOpHash,
|
||||||
|
//! # };
|
||||||
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
|
//! # type Hash = sha2::Sha256;
|
||||||
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
|
//! # }
|
||||||
|
//! # use rand_core::{OsRng, RngCore};
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # )?;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
||||||
|
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&mut server_rng, client_registration_start_result.message, server_kp.public())?;
|
||||||
|
//! // During registration...
|
||||||
|
//! let client_registration_finish_result = client_registration_start_result.state.finish(
|
||||||
|
//! &mut client_rng,
|
||||||
|
//! server_registration_start_result.message,
|
||||||
|
//! ClientRegistrationFinishParameters::default()
|
||||||
|
//! )?;
|
||||||
|
//! # 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(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # ClientLoginStartParameters::default(),
|
||||||
|
//! # )?;
|
||||||
|
//! # use std::convert::TryFrom;
|
||||||
|
//! # let password_file =
|
||||||
|
//! # ServerRegistration::<Default>::try_from(
|
||||||
|
//! # &password_file_bytes[..],
|
||||||
|
//! # )?;
|
||||||
|
//! # let server_login_start_result =
|
||||||
|
//! # ServerLogin::start(&mut server_rng, password_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default())?;
|
||||||
|
//!
|
||||||
|
//! // And then later, during login...
|
||||||
|
//! let client_login_finish_result = client_login_start_result.state.finish(
|
||||||
|
//! server_login_start_result.message,
|
||||||
|
//! ClientLoginFinishParameters::default(),
|
||||||
|
//! )?;
|
||||||
|
//!
|
||||||
|
//! assert_eq!(
|
||||||
|
//! client_registration_finish_result.export_key,
|
||||||
|
//! client_login_finish_result.export_key,
|
||||||
|
//! );
|
||||||
|
//! # Ok::<(), ProtocolError>(())
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Custom Identifiers
|
||||||
|
//!
|
||||||
|
//! Typically when applications use OPAQUE to authenticate a client to a server, the client has a registered "username" which is sent to the server to
|
||||||
|
//! identify the corresponding password file established during registration. The server may also have an identifier corresponding to an entity (e.g. facebook.com).
|
||||||
|
//! By default, neither of these public identifiers need to be supplied to the OPAQUE protocol.
|
||||||
|
//!
|
||||||
|
//! But, for applications that wish to cryptographically bind these identities to
|
||||||
|
//! the registered password file as well as the shared secret output by the login phase, these custom identifiers can be specified through
|
||||||
|
//! [ClientRegistrationFinishParameters::WithIdentifiers] in [Client Registration Finish](#client-registration-finish):
|
||||||
|
//! ```
|
||||||
|
//! # use opaque_ke::{
|
||||||
|
//! # errors::ProtocolError,
|
||||||
|
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration,
|
||||||
|
//! # keypair::{KeyPair, X25519KeyPair},
|
||||||
|
//! # slow_hash::NoOpHash,
|
||||||
|
//! # };
|
||||||
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
|
//! # type Hash = sha2::Sha256;
|
||||||
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
|
//! # }
|
||||||
|
//! # use rand_core::{OsRng, RngCore};
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # )?;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server_kp = Default::generate_random_keypair(&mut server_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,
|
||||||
|
//! ClientRegistrationFinishParameters::WithIdentifiers(
|
||||||
|
//! b"username".to_vec(),
|
||||||
|
//! b"facebook.com".to_vec(),
|
||||||
|
//! ),
|
||||||
|
//! )?;
|
||||||
|
//! # Ok::<(), ProtocolError>(())
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The same identifiers must also be supplied using [ServerLoginStartParameters::WithIdentifiers] in [Server Login Start](#server-login-start):
|
||||||
|
//! ```
|
||||||
|
//! # use opaque_ke::{
|
||||||
|
//! # errors::ProtocolError,
|
||||||
|
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, CredentialFinalization,
|
||||||
|
//! # keypair::{KeyPair, X25519KeyPair},
|
||||||
|
//! # slow_hash::NoOpHash,
|
||||||
|
//! # };
|
||||||
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
|
//! # type Hash = sha2::Sha256;
|
||||||
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
|
//! # }
|
||||||
|
//! # use rand_core::{OsRng, RngCore};
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # )?;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server_kp = Default::generate_random_keypair(&mut server_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, ClientRegistrationFinishParameters::WithIdentifiers(b"username".to_vec(), b"facebook.com".to_vec()))?;
|
||||||
|
//! # 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(
|
||||||
|
//! # &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(
|
||||||
|
//! &mut server_rng,
|
||||||
|
//! password_file,
|
||||||
|
//! &server_kp.private(),
|
||||||
|
//! client_login_start_result.message,
|
||||||
|
//! ServerLoginStartParameters::WithIdentifiers(
|
||||||
|
//! b"username".to_vec(),
|
||||||
|
//! b"facebook.com".to_vec(),
|
||||||
|
//! ),
|
||||||
|
//! )?;
|
||||||
|
//! # Ok::<(), ProtocolError>(())
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! as well as [ClientLoginFinishParameters::WithIdentifiers] in [Client Login Finish](#client-login-finish):
|
||||||
|
//! ```
|
||||||
|
//! # use opaque_ke::{
|
||||||
|
//! # errors::ProtocolError,
|
||||||
|
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, CredentialFinalization,
|
||||||
|
//! # keypair::{KeyPair, X25519KeyPair},
|
||||||
|
//! # slow_hash::NoOpHash,
|
||||||
|
//! # };
|
||||||
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
||||||
|
//! # struct Default;
|
||||||
|
//! # impl CipherSuite for Default {
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||||
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
|
//! # type Hash = sha2::Sha256;
|
||||||
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
|
//! # }
|
||||||
|
//! # use rand_core::{OsRng, RngCore};
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # )?;
|
||||||
|
//! # let mut server_rng = OsRng;
|
||||||
|
//! # let server_kp = Default::generate_random_keypair(&mut server_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, ClientRegistrationFinishParameters::WithIdentifiers(b"username".to_vec(), b"facebook.com".to_vec()))?;
|
||||||
|
//! # 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(
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # b"password",
|
||||||
|
//! # ClientLoginStartParameters::default(),
|
||||||
|
//! # )?;
|
||||||
|
//! # use std::convert::TryFrom;
|
||||||
|
//! # let password_file =
|
||||||
|
//! # ServerRegistration::<Default>::try_from(
|
||||||
|
//! # &password_file_bytes[..],
|
||||||
|
//! # )?;
|
||||||
|
//! # let server_login_start_result =
|
||||||
|
//! # ServerLogin::start(&mut server_rng, password_file, &server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::WithIdentifiers(b"username".to_vec(), b"facebook.com".to_vec()))?;
|
||||||
|
//! let client_login_finish_result = client_login_start_result.state.finish(
|
||||||
|
//! server_login_start_result.message,
|
||||||
|
//! ClientLoginFinishParameters::WithIdentifiers(
|
||||||
|
//! b"username".to_vec(),
|
||||||
|
//! b"facebook.com".to_vec(),
|
||||||
|
//! ),
|
||||||
|
//! )?;
|
||||||
|
//! # Ok::<(), ProtocolError>(())
|
||||||
|
//! ```
|
||||||
|
//! Failing to supply the same pair of custom identifiers in any of the three steps above will result in an error in attempting to complete
|
||||||
|
//! the protocol!
|
||||||
|
//!
|
||||||
|
//! ## Key Exchange Additional Data
|
||||||
|
//!
|
||||||
|
//! A key exchange protocol typically supports the passing of data between the two parties before the exchange is complete, so as to bind the integrity
|
||||||
|
//! and/or confidentiality of application-specific data to the security of the key exchange. During the login phase, the client and server can pass
|
||||||
|
//! additional data alongside the first three messages of the protocol, with confidential data being supported for the second and third messages.
|
||||||
|
//!
|
||||||
|
//! The following three messages support passing of additional data:
|
||||||
|
//! - The first login message, where the client can populate [ClientLoginStartParameters::WithInfo] with plaintext additional data, and
|
||||||
|
//! the server can retrieve using the `plain_info` field of [ServerLoginStartResult].
|
||||||
|
//! - The second login message, where the server can populate [ServerLoginStartParameters::WithInfo] with plaintext and confidential additional data,
|
||||||
|
//! and the client can retrieve using the `plain_info` and `confidential_info` fields of [ClientLoginFinishResult].
|
||||||
|
//! - The third login message, where the client can populate [ClientLoginFinishParameters::WithInfo] with plaintext and confidential
|
||||||
|
//! additional info, and the server can retrieve using the `plain_info` and `confidential_info` fields of [ServerLoginFinishResult].
|
||||||
|
//!
|
||||||
|
//! The `WithInfoAndIdentifiers` variant of each of these enums representing optional parameters can be used to specify these fields in addition to
|
||||||
|
//! [custom identifiers](#custom-identifiers), with the ordering of the fields as `WithInfoAndIdentifiers(plain_info, confidential_info, username, server_name)`.
|
||||||
|
//!
|
||||||
//!
|
//!
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
||||||
|
|||||||
+17
-23
@@ -483,7 +483,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
|
|
||||||
/// Optional parameters for client login start
|
/// Optional parameters for client login start
|
||||||
pub enum ClientLoginStartParameters {
|
pub enum ClientLoginStartParameters {
|
||||||
/// Specifying an info field that will be sent to the server
|
/// Specifying a plaintext info field that will be sent to the server
|
||||||
WithInfo(Vec<u8>),
|
WithInfo(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,12 +503,13 @@ pub struct ClientLoginStartResult<CS: CipherSuite> {
|
|||||||
|
|
||||||
/// Optional parameters for client login finish
|
/// Optional parameters for client login finish
|
||||||
pub enum ClientLoginFinishParameters {
|
pub enum ClientLoginFinishParameters {
|
||||||
/// Specifying an info and confidential info field that will be sent to the server
|
/// Specifying a plaintext info and confidential info field that will be sent to the server
|
||||||
WithInfo(Vec<u8>, Vec<u8>),
|
WithInfo(Vec<u8>, Vec<u8>),
|
||||||
/// Specifying an id_u and id_s that will be matched against the server
|
/// Specifying a user identifier and server identifier that will be matched against the client
|
||||||
WithIdentifiers(Vec<u8>, Vec<u8>),
|
WithIdentifiers(Vec<u8>, Vec<u8>),
|
||||||
/// Specifying an info, confidential info that will be sent to the server,
|
/// Specifying a plaintext info and confidential info that will be sent to the server,
|
||||||
/// along with an id_u and id_s that will be matched against the server
|
/// along with a user identifier and and server identifier that will be matched against the server
|
||||||
|
/// (in that order)
|
||||||
WithInfoAndIdentifiers(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>),
|
WithInfoAndIdentifiers(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>),
|
||||||
/// No info and no custom identifiers
|
/// No info and no custom identifiers
|
||||||
Default,
|
Default,
|
||||||
@@ -529,7 +530,7 @@ pub struct ClientLoginFinishResult<CS: CipherSuite> {
|
|||||||
/// 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: <CS::KeyFormat as KeyPair>::Repr,
|
||||||
/// 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
|
||||||
@@ -639,17 +640,14 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let l2_beta_bytes = &l2.beta.to_arr()[..];
|
let l2_beta_bytes = &l2.beta.to_arr()[..];
|
||||||
|
let server_s_pk_bytes = l2.server_s_pk.to_arr().to_vec();
|
||||||
|
|
||||||
let password_derived_key =
|
let password_derived_key =
|
||||||
get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>(&self.token, l2.beta)?;
|
get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>(&self.token, l2.beta)?;
|
||||||
|
|
||||||
let opened_envelope = &l2
|
let opened_envelope = &l2
|
||||||
.envelope
|
.envelope
|
||||||
.open(
|
.open(&password_derived_key, &server_s_pk_bytes, &optional_ids)
|
||||||
&password_derived_key,
|
|
||||||
&l2.server_s_pk.to_arr().to_vec(),
|
|
||||||
&optional_ids,
|
|
||||||
)
|
|
||||||
.map_err(|e| match e {
|
.map_err(|e| match e {
|
||||||
InternalPakeError::SealOpenHmacError => PakeError::InvalidLoginError,
|
InternalPakeError::SealOpenHmacError => PakeError::InvalidLoginError,
|
||||||
err => PakeError::from(err),
|
err => PakeError::from(err),
|
||||||
@@ -658,8 +656,6 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
let client_s_sk =
|
let client_s_sk =
|
||||||
<CS::KeyFormat as KeyPair>::Repr::from_bytes(&opened_envelope.client_s_sk)?;
|
<CS::KeyFormat as KeyPair>::Repr::from_bytes(&opened_envelope.client_s_sk)?;
|
||||||
|
|
||||||
let server_s_pk_bytes = l2.server_s_pk.to_arr().to_vec();
|
|
||||||
|
|
||||||
let (id_u, id_s) = match optional_ids {
|
let (id_u, id_s) = match optional_ids {
|
||||||
None => (
|
None => (
|
||||||
CS::KeyFormat::public_from_private(&client_s_sk)
|
CS::KeyFormat::public_from_private(&client_s_sk)
|
||||||
@@ -682,7 +678,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
l2_bytes,
|
l2_bytes,
|
||||||
l2.ke2_message,
|
l2.ke2_message,
|
||||||
&self.ke1_state,
|
&self.ke1_state,
|
||||||
l2.server_s_pk,
|
l2.server_s_pk.clone(),
|
||||||
client_s_sk,
|
client_s_sk,
|
||||||
id_u,
|
id_u,
|
||||||
id_s,
|
id_s,
|
||||||
@@ -696,7 +692,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
message: CredentialFinalization { ke3_message },
|
message: CredentialFinalization { ke3_message },
|
||||||
shared_secret,
|
shared_secret,
|
||||||
export_key: opened_envelope.export_key,
|
export_key: opened_envelope.export_key,
|
||||||
server_s_pk: server_s_pk_bytes,
|
server_s_pk: l2.server_s_pk,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -722,12 +718,13 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ServerLogin<CS> {
|
|||||||
|
|
||||||
/// Optional parameters for server login start
|
/// Optional parameters for server login start
|
||||||
pub enum ServerLoginStartParameters {
|
pub enum ServerLoginStartParameters {
|
||||||
/// Specifying an info and confidential info field that will be sent to the client
|
/// Specifying a plaintext info and confidential info field that will be sent to the client
|
||||||
WithInfo(Vec<u8>, Vec<u8>),
|
WithInfo(Vec<u8>, Vec<u8>),
|
||||||
/// Specifying an id_u and id_s that will be matched against the client
|
/// Specifying a user identifier and server identifier that will be matched against the client
|
||||||
WithIdentifiers(Vec<u8>, Vec<u8>),
|
WithIdentifiers(Vec<u8>, Vec<u8>),
|
||||||
/// Specifying an info, confidential info that will be sent to the client,
|
/// Specifying a plaintext info and confidential info that will be sent to the client,
|
||||||
/// along with an id_u and id_s that will be matched against the client
|
/// along with a user identifier and and server identifier that will be matched against the client
|
||||||
|
/// (in that order)
|
||||||
WithInfoAndIdentifiers(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>),
|
WithInfoAndIdentifiers(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,8 +740,6 @@ pub struct ServerLoginStartResult<CS: CipherSuite> {
|
|||||||
pub message: CredentialResponse<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 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
|
/// The plaintext info sent by the client
|
||||||
pub plain_info: Vec<u8>,
|
pub plain_info: Vec<u8>,
|
||||||
}
|
}
|
||||||
@@ -852,7 +847,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
|||||||
l1_bytes.to_vec(),
|
l1_bytes.to_vec(),
|
||||||
l2_component,
|
l2_component,
|
||||||
l1.ke1_message,
|
l1.ke1_message,
|
||||||
client_s_pk.clone(),
|
client_s_pk,
|
||||||
server_s_sk.clone(),
|
server_s_sk.clone(),
|
||||||
id_u,
|
id_u,
|
||||||
id_s,
|
id_s,
|
||||||
@@ -874,7 +869,6 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
|||||||
_cs: PhantomData,
|
_cs: PhantomData,
|
||||||
ke2_state,
|
ke2_state,
|
||||||
},
|
},
|
||||||
client_s_pk: client_s_pk.to_arr().to_vec(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -592,10 +592,6 @@ fn test_credential_response() -> Result<(), ProtocolError> {
|
|||||||
hex::encode(¶meters.info1),
|
hex::encode(¶meters.info1),
|
||||||
hex::encode(server_login_start_result.plain_info),
|
hex::encode(server_login_start_result.plain_info),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
hex::encode(¶meters.client_s_pk),
|
|
||||||
hex::encode(server_login_start_result.client_s_pk),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(¶meters.credential_response),
|
hex::encode(¶meters.credential_response),
|
||||||
hex::encode(server_login_start_result.message.serialize())
|
hex::encode(server_login_start_result.message.serialize())
|
||||||
@@ -636,7 +632,7 @@ fn test_key_exchange() -> Result<(), ProtocolError> {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(¶meters.server_s_pk),
|
hex::encode(¶meters.server_s_pk),
|
||||||
hex::encode(&client_login_finish_result.server_s_pk)
|
hex::encode(&client_login_finish_result.server_s_pk.to_arr().to_vec())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(¶meters.shared_secret),
|
hex::encode(¶meters.shared_secret),
|
||||||
|
|||||||
Reference in New Issue
Block a user