2020-06-05 09:35:14 -07:00
|
|
|
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
|
//
|
|
|
|
|
// This source code is licensed under the MIT license found in the
|
|
|
|
|
// LICENSE file in the root directory of this source tree.
|
|
|
|
|
|
|
|
|
|
//! An implementation of the OPAQUE asymmetric password authentication key exchange protocol
|
|
|
|
|
//!
|
2020-07-02 12:24:53 -07:00
|
|
|
//! Note: This implementation is in sync with [draft-krawczyk-cfrg-opaque-06](https://tools.ietf.org/html/draft-krawczyk-cfrg-opaque-06),
|
2020-06-09 15:13:42 -07:00
|
|
|
//! but this specification is subject to change, until the final version published by the IETF.
|
|
|
|
|
//!
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # Overview
|
|
|
|
|
//!
|
|
|
|
|
//! OPAQUE is a protocol between a client and a server. They must first agree on a collection of primitives
|
|
|
|
|
//! to be kept consistent throughout protocol execution. These include:
|
2020-06-14 23:25:31 -07:00
|
|
|
//! * a finite cyclic group along with a point representation,
|
2020-07-13 15:23:29 -07:00
|
|
|
//! * a keypair type,
|
2020-07-27 15:25:04 -07:00
|
|
|
//! * a key exchange protocol,
|
|
|
|
|
//! * a hashing function, and
|
2020-06-14 23:25:31 -07:00
|
|
|
//! * a slow hashing function.
|
2020-06-05 09:35:14 -07:00
|
|
|
//!
|
|
|
|
|
//! We will use the following choices in this example:
|
|
|
|
|
//! ```
|
2020-06-14 23:25:31 -07:00
|
|
|
//! use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! struct Default;
|
|
|
|
|
//! impl CipherSuite for Default {
|
|
|
|
|
//! type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! ```
|
|
|
|
|
//!
|
2020-06-08 21:02:01 -07:00
|
|
|
//! 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`.
|
|
|
|
|
//!
|
2020-06-09 15:13:42 -07:00
|
|
|
//! We have included a concrete instantiation of the authenticated key exchange protocol using 3DH. In the future, we plan to
|
2020-06-05 09:35:14 -07:00
|
|
|
//! add support for other KE protocols as well.
|
|
|
|
|
//!
|
|
|
|
|
//! ## Setup
|
|
|
|
|
//! To setup the protocol, the server begins by generating a static keypair:
|
|
|
|
|
//! ```
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # use opaque_ke::keypair::{KeyPair, X25519KeyPair};
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use opaque_ke::errors::ProtocolError;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! let mut rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! let server_kp = Default::generate_random_keypair(&mut rng)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # Ok::<(), ProtocolError>(())
|
|
|
|
|
//! ```
|
|
|
|
|
//! The server must persist this keypair for the registration and login steps, where the public component will be
|
|
|
|
|
//! 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 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`:
|
|
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ServerRegistration,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-11-16 14:05:43 -08:00
|
|
|
//! use opaque_ke::{ClientRegistration, ClientRegistrationStartParameters};
|
2020-06-05 09:35:14 -07:00
|
|
|
//! use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! let mut client_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! let (r1, client_state) = ClientRegistration::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! b"password",
|
2020-11-16 14:05:43 -08:00
|
|
|
//! ClientRegistrationStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! &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`:
|
|
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistration, ClientRegistrationStartParameters,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! # let mut client_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistrationStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &mut client_rng,
|
|
|
|
|
//! # )?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! use opaque_ke::ServerRegistration;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! let mut server_rng = OsRng;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
|
|
|
|
//! let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # 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
|
2020-07-02 12:24:53 -07:00
|
|
|
//! `finish` and produce a message `r3` along with the export key `export_key_registration`:
|
2020-06-05 09:35:14 -07:00
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! # let mut client_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistrationStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &mut client_rng,
|
|
|
|
|
//! # )?;
|
|
|
|
|
//! # let mut server_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # let (r2, server_state) = ServerRegistration::<Default>::start(r1, server_kp.public(), &mut server_rng)?;
|
2020-07-02 12:24:53 -07:00
|
|
|
//! let (r3, export_key_registration) =
|
2020-11-16 14:05:43 -08:00
|
|
|
//! client_state.finish(r2, &mut client_rng)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # Ok::<(), ProtocolError>(())
|
|
|
|
|
//! ```
|
2020-07-02 12:24:53 -07:00
|
|
|
//! `r3` is sent to the server, and the client can optionally use `export_key_registration` for applications that choose to
|
2020-06-05 09:35:14 -07:00
|
|
|
//! 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`:
|
|
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! # let mut client_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistrationStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &mut client_rng,
|
|
|
|
|
//! # )?;
|
|
|
|
|
//! # let mut server_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # 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)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! let password_file = server_state.finish(r3)?;
|
|
|
|
|
//! # 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.
|
|
|
|
|
//!
|
|
|
|
|
//! 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`:
|
|
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistration, ServerRegistration, ServerLogin, LoginThirdMessage,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use rand_core::{OsRng, RngCore};
|
2020-11-16 14:05:43 -08:00
|
|
|
//! use opaque_ke::{ClientLogin, ClientLoginStartParameters};
|
2020-06-05 09:35:14 -07:00
|
|
|
//! let mut client_rng = OsRng;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! let client_login_start_result = ClientLogin::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! b"password",
|
|
|
|
|
//! &mut client_rng,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! ClientLoginStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! )?;
|
|
|
|
|
//! # Ok::<(), ProtocolError>(())
|
|
|
|
|
//! ```
|
2020-11-16 14:05:43 -08:00
|
|
|
//! `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.
|
2020-06-05 09:35:14 -07:00
|
|
|
//!
|
|
|
|
|
//! 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
|
2020-11-16 14:05:43 -08:00
|
|
|
//! runs `ServerLogin::start` to produce `server_login_start_result`:
|
2020-06-05 09:35:14 -07:00
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, LoginThirdMessage,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! # let mut client_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistrationStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &mut client_rng,
|
|
|
|
|
//! # )?;
|
|
|
|
|
//! # let mut server_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # 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)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # let client_login_start_result = ClientLogin::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
|
|
|
|
//! # &mut client_rng,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientLoginStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # )?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! use opaque_ke::{ServerLogin, ServerLoginStartParameters};
|
2020-06-05 09:35:14 -07:00
|
|
|
//! use std::convert::TryFrom;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! let password_file = ServerRegistration::<Default>::try_from(&password_file_bytes[..])?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! let mut server_rng = OsRng;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! let server_login_start_result =
|
|
|
|
|
//! ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # Ok::<(), ProtocolError>(())
|
|
|
|
|
//! ```
|
2020-11-16 14:05:43 -08:00
|
|
|
//! `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.
|
2020-06-05 09:35:14 -07:00
|
|
|
//!
|
|
|
|
|
//! 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
|
2020-07-02 12:24:53 -07:00
|
|
|
//! a message `l3`, the shared secret `client_shared_secret`, and the export key `export_key_login`:
|
2020-06-05 09:35:14 -07:00
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! # let mut client_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistrationStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &mut client_rng,
|
|
|
|
|
//! # )?;
|
|
|
|
|
//! # let mut server_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # 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)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # let client_login_start_result = ClientLogin::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
|
|
|
|
//! # &mut client_rng,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientLoginStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # )?;
|
|
|
|
|
//! # use std::convert::TryFrom;
|
|
|
|
|
//! # let password_file =
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # ServerRegistration::<Default>::try_from(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &password_file_bytes[..],
|
|
|
|
|
//! # )?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # let server_login_start_result =
|
|
|
|
|
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
|
|
|
|
|
//! let client_login_finish_result = client_login_start_result.client_login_state.finish(
|
|
|
|
|
//! server_login_start_result.credential_response,
|
|
|
|
|
//! ClientLoginFinishParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! )?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! assert_eq!(export_key_registration, client_login_finish_result.export_key);
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # 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
|
2020-07-02 12:24:53 -07:00
|
|
|
//! can use `export_key_login` for applications that can take advantage of the fact that this key is identical to
|
|
|
|
|
//! `export_key_registration`.
|
2020-06-05 09:35:14 -07:00
|
|
|
//!
|
|
|
|
|
//! 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`:
|
|
|
|
|
//! ```
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # use opaque_ke::{
|
|
|
|
|
//! # errors::ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistration, ClientRegistrationStartParameters, ServerRegistration, ClientLogin, ClientLoginStartParameters, ClientLoginFinishParameters, ServerLogin, ServerLoginStartParameters, LoginThirdMessage,
|
2020-11-03 21:44:00 +00:00
|
|
|
//! # keypair::{KeyPair, X25519KeyPair},
|
2020-06-08 21:02:01 -07:00
|
|
|
//! # slow_hash::NoOpHash,
|
|
|
|
|
//! # };
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # use opaque_ke::ciphersuite::CipherSuite;
|
|
|
|
|
//! # struct Default;
|
|
|
|
|
//! # impl CipherSuite for Default {
|
|
|
|
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
|
|
//! # type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
2020-07-13 15:23:29 -07:00
|
|
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
2020-07-27 15:25:04 -07:00
|
|
|
//! # type Hash = sha2::Sha256;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
|
|
|
|
//! # }
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # use rand_core::{OsRng, RngCore};
|
|
|
|
|
//! # let mut client_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let (r1, client_state) = ClientRegistration::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientRegistrationStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &mut client_rng,
|
|
|
|
|
//! # )?;
|
|
|
|
|
//! # let mut server_rng = OsRng;
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # let server_kp = Default::generate_random_keypair(&mut server_rng)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # 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)?;
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # let password_file_bytes = server_state.finish(r3)?.to_bytes();
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # let client_login_start_result = ClientLogin::<Default>::start(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # b"password",
|
|
|
|
|
//! # &mut client_rng,
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # ClientLoginStartParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # )?;
|
|
|
|
|
//! # use std::convert::TryFrom;
|
|
|
|
|
//! # let password_file =
|
2020-06-14 23:25:31 -07:00
|
|
|
//! # ServerRegistration::<Default>::try_from(
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # &password_file_bytes[..],
|
|
|
|
|
//! # )?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! # let server_login_start_result =
|
|
|
|
|
//! # ServerLogin::start(password_file, &server_kp.private(), client_login_start_result.credential_request, &mut server_rng, ServerLoginStartParameters::default())?;
|
|
|
|
|
//! # let client_login_finish_result = client_login_start_result.client_login_state.finish(
|
|
|
|
|
//! # server_login_start_result.credential_response,
|
|
|
|
|
//! # ClientLoginFinishParameters::default(),
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # )?;
|
2020-11-16 14:05:43 -08:00
|
|
|
//! 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);
|
2020-06-05 09:35:14 -07:00
|
|
|
//! # 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`.
|
|
|
|
|
//!
|
|
|
|
|
|
2020-07-22 14:27:41 -04:00
|
|
|
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
2020-07-06 15:40:35 -04:00
|
|
|
#![deny(unsafe_code)]
|
|
|
|
|
|
2020-07-22 14:53:59 -04:00
|
|
|
#[cfg(not(any(feature = "u64_backend", feature = "u32_backend",)))]
|
|
|
|
|
compile_error!(
|
|
|
|
|
"no dalek arithmetic backend cargo feature enabled! \
|
|
|
|
|
please enable one of: u64_backend, u32_backend"
|
|
|
|
|
);
|
|
|
|
|
|
2020-06-05 09:35:14 -07:00
|
|
|
// Error types
|
|
|
|
|
pub mod errors;
|
2020-07-02 12:24:53 -07:00
|
|
|
|
2020-06-05 09:35:14 -07:00
|
|
|
// High-level API
|
2020-11-16 14:05:43 -08:00
|
|
|
mod opaque;
|
|
|
|
|
|
|
|
|
|
mod messages;
|
2020-06-05 09:35:14 -07:00
|
|
|
|
2020-06-14 23:25:31 -07:00
|
|
|
pub mod ciphersuite;
|
2020-07-02 12:24:53 -07:00
|
|
|
mod envelope;
|
2020-10-21 18:20:43 -04:00
|
|
|
pub mod hash;
|
2020-07-03 18:28:35 -04:00
|
|
|
|
2020-09-02 15:06:24 -04:00
|
|
|
mod elligator;
|
2020-07-22 11:58:00 -04:00
|
|
|
pub mod group;
|
2020-09-02 15:06:24 -04:00
|
|
|
|
2020-07-22 11:58:00 -04:00
|
|
|
pub mod map_to_curve;
|
2020-07-03 18:28:35 -04:00
|
|
|
|
2020-07-13 15:23:29 -07:00
|
|
|
pub mod key_exchange;
|
2020-06-05 09:35:14 -07:00
|
|
|
pub mod keypair;
|
2020-07-03 18:28:35 -04:00
|
|
|
|
2020-07-22 14:27:41 -04:00
|
|
|
#[cfg(feature = "bench")]
|
|
|
|
|
pub mod oprf;
|
|
|
|
|
#[cfg(not(feature = "bench"))]
|
2020-06-05 09:35:14 -07:00
|
|
|
mod oprf;
|
2020-07-22 14:27:41 -04:00
|
|
|
|
2020-06-08 21:02:01 -07:00
|
|
|
pub mod slow_hash;
|
2020-06-05 09:35:14 -07:00
|
|
|
|
2020-08-14 16:20:42 -04:00
|
|
|
mod serialization;
|
|
|
|
|
|
2020-06-05 09:35:14 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests;
|
2020-11-16 14:05:43 -08:00
|
|
|
|
|
|
|
|
// Exports
|
|
|
|
|
|
|
|
|
|
pub use crate::messages::{
|
|
|
|
|
LoginFirstMessage, LoginSecondMessage, LoginThirdMessage, RegisterFirstMessage,
|
|
|
|
|
RegisterSecondMessage, RegisterThirdMessage,
|
|
|
|
|
};
|
|
|
|
|
pub use crate::opaque::{ClientLogin, ClientRegistration, ServerLogin, ServerRegistration};
|
|
|
|
|
pub use crate::opaque::{
|
|
|
|
|
ClientLoginFinishParameters, ClientLoginStartParameters, ClientRegistrationStartParameters,
|
|
|
|
|
ServerLoginStartParameters,
|
|
|
|
|
};
|