opaque_ke/
lib.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is dual-licensed under either the MIT license found in the
4// LICENSE-MIT file in the root directory of this source tree or the Apache
5// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
6// of this source tree. You may select, at your option, one of the above-listed
7// licenses.
8
9//! An implementation of the OPAQUE augmented password authentication key
10//! exchange protocol
11//!
12//! ### Minimum Supported Rust Version
13//!
14//! Rust **1.85** or higher.
15//!
16//! # Overview
17//!
18//! OPAQUE is a protocol between a client and a server. They must first agree on
19//! a collection of primitives to be kept consistent throughout protocol
20//! execution. These include:
21//! * a finite cyclic group along with a point representation
22//!   * for the OPRF and
23//!   * for the key exchange
24//! * a key exchange protocol,
25//! * a hashing function, and
26//! * a key stretching function.
27//!
28//! We will use the following choices in this example:
29//! ```ignore
30//! use opaque_ke::CipherSuite;
31//!
32//! struct Default;
33//!
34//! impl CipherSuite for Default {
35//!     type OprfCs = opaque_ke::Ristretto255;
36//!     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
37//!     type Ksf = opaque_ke::ksf::Identity;
38//! }
39//! ```
40//! See [examples/simple_login.rs](https://github.com/facebook/opaque-ke/blob/main/examples/simple_login.rs)
41//! for a working example of a simple password-based login using OPAQUE.
42//!
43//! Note that our choice of key stretching function in this example, `Identity`,
44//! is selected only to ensure that the tests execute quickly. A real
45//! application should use an actual key stretching function, such as `Argon2`,
46//! which can be enabled through the `argon2` feature. See more details in
47//! the [features](#features) section.
48//!
49//! ## Setup
50//! To set up the protocol, the server begins by creating a `ServerSetup`
51//! object:
52//! ```
53//! # use opaque_ke::errors::ProtocolError;
54//! # use opaque_ke::CipherSuite;
55//! # use opaque_ke::ServerSetup;
56//! # struct Default;
57//! # #[cfg(feature = "ristretto255")]
58//! # impl CipherSuite for Default {
59//! #     type OprfCs = opaque_ke::Ristretto255;
60//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
61//! #     type Ksf = opaque_ke::ksf::Identity;
62//! # }
63//! # #[cfg(not(feature = "ristretto255"))]
64//! # impl CipherSuite for Default {
65//! #     type OprfCs = p256::NistP256;
66//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
67//! #     type Ksf = opaque_ke::ksf::Identity;
68//! # }
69//! use rand::RngCore;
70//! use rand::rngs::OsRng;
71//!
72//! let mut rng = OsRng;
73//! let server_setup = ServerSetup::<Default>::new(&mut rng);
74//! # Ok::<(), ProtocolError>(())
75//! ```
76//! The server must persist an instance of [`ServerSetup`] for the registration
77//! and login steps, and can use [`ServerSetup::serialize`] and
78//! [`ServerSetup::deserialize`] to save and restore the instance.
79//!
80//! ## Registration
81//! The registration protocol between the client and server consists of four
82//! steps along with three messages: [`RegistrationRequest`],
83//! [`RegistrationResponse`], and [`RegistrationUpload`]. A successful execution
84//! of the registration protocol results in the server producing a password file
85//! corresponding to a server-side identifier for the client, along with the
86//! password provided by the client. This password file is typically stored in a
87//! key-value database, where the keys consist of these server-side identifiers
88//! for each client, and the values consist of their corresponding password
89//! files, to be retrieved upon future login attempts made by the client.
90//! It is your responsibility to ensure that the identifier used to form the
91//! initial [`RegistrationRequest`], typically supplied by the client, matches
92//! the database key used in the final [`RegistrationUpload`] step.
93//!
94//! Note that the [`RegistrationUpload`] message contains sensitive information
95//! (about as sensitive as a hash of the password), and hence should be
96//! protected with confidentiality guarantees by the consumer of this library.
97//!
98//! ### Client Registration Start
99//! In the first step of registration, the client chooses as input a
100//! registration password. The client runs [`ClientRegistration::start`] to
101//! produce a [`ClientRegistrationStartResult`], which consists of a
102//! [`RegistrationRequest`] to be sent to the server and a
103//! [`ClientRegistration`] which must be persisted on the client for the final
104//! step of client registration.
105//! ```
106//! # use opaque_ke::{
107//! #   errors::ProtocolError,
108//! #   ServerRegistration,
109//! #   ksf::Identity,
110//! # };
111//! # use opaque_ke::CipherSuite;
112//! # struct Default;
113//! # #[cfg(feature = "ristretto255")]
114//! # impl CipherSuite for Default {
115//! #     type OprfCs = opaque_ke::Ristretto255;
116//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
117//! #     type Ksf = opaque_ke::ksf::Identity;
118//! # }
119//! # #[cfg(not(feature = "ristretto255"))]
120//! # impl CipherSuite for Default {
121//! #     type OprfCs = p256::NistP256;
122//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
123//! #     type Ksf = opaque_ke::ksf::Identity;
124//! # }
125//! use opaque_ke::ClientRegistration;
126//! use rand::RngCore;
127//! use rand::rngs::OsRng;
128//!
129//! let mut client_rng = OsRng;
130//! let client_registration_start_result =
131//!     ClientRegistration::<Default>::start(&mut client_rng, b"password")?;
132//! # Ok::<(), ProtocolError>(())
133//! ```
134//!
135//! ### Server Registration Start
136//! In the second step of registration, the server takes as input a persisted
137//! instance of [`ServerSetup`], a [`RegistrationRequest`] from the client, and
138//! a server-side identifier for the client. The server runs
139//! [`ServerRegistration::start`] to produce a
140//! [`ServerRegistrationStartResult`], which consists of a
141//! [`RegistrationResponse`] to be returned to the client.
142//! ```
143//! # use opaque_ke::{
144//! #   errors::ProtocolError,
145//! #   ClientRegistration,
146//! #   ServerSetup,
147//! #   ksf::Identity,
148//! # };
149//! # use opaque_ke::CipherSuite;
150//! # struct Default;
151//! # #[cfg(feature = "ristretto255")]
152//! # impl CipherSuite for Default {
153//! #     type OprfCs = opaque_ke::Ristretto255;
154//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
155//! #     type Ksf = opaque_ke::ksf::Identity;
156//! # }
157//! # #[cfg(not(feature = "ristretto255"))]
158//! # impl CipherSuite for Default {
159//! #     type OprfCs = p256::NistP256;
160//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
161//! #     type Ksf = opaque_ke::ksf::Identity;
162//! # }
163//! # use rand::{rngs::OsRng, RngCore};
164//! # let mut client_rng = OsRng;
165//! # let client_registration_start_result = ClientRegistration::<Default>::start(
166//! #     &mut client_rng,
167//! #     b"password",
168//! # )?;
169//! use opaque_ke::ServerRegistration;
170//!
171//! # let mut server_rng = OsRng;
172//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
173//! let server_registration_start_result = ServerRegistration::<Default>::start(
174//!     &server_setup,
175//!     client_registration_start_result.message,
176//!     b"alice@example.com",
177//! )?;
178//! # Ok::<(), ProtocolError>(())
179//! ```
180//!
181//! ### Client Registration Finish
182//! In the third step of registration, the client takes as input a
183//! [`RegistrationResponse`] from the server, and a [`ClientRegistration`] from
184//! the first step of registration. The client runs
185//! [`ClientRegistration::finish`] to
186//! produce a [`ClientRegistrationFinishResult`], which consists of a
187//! [`RegistrationUpload`] to be sent to the server and an `export_key` field
188//! which can be used optionally as described in the [Export Key](#export-key)
189//! section.
190//! ```
191//! # use opaque_ke::{
192//! #   errors::ProtocolError,
193//! #   ClientRegistration, ServerRegistration, ServerSetup,
194//! #   ksf::Identity,
195//! # };
196//! # use opaque_ke::CipherSuite;
197//! # struct Default;
198//! # #[cfg(feature = "ristretto255")]
199//! # impl CipherSuite for Default {
200//! #     type OprfCs = opaque_ke::Ristretto255;
201//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
202//! #     type Ksf = opaque_ke::ksf::Identity;
203//! # }
204//! # #[cfg(not(feature = "ristretto255"))]
205//! # impl CipherSuite for Default {
206//! #     type OprfCs = p256::NistP256;
207//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
208//! #     type Ksf = opaque_ke::ksf::Identity;
209//! # }
210//! # use rand::{rngs::OsRng, RngCore};
211//! # let mut client_rng = OsRng;
212//! # let client_registration_start_result = ClientRegistration::<Default>::start(
213//! #     &mut client_rng,
214//! #     b"password",
215//! # )?;
216//! # let mut server_rng = OsRng;
217//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
218//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
219//! use opaque_ke::ClientRegistrationFinishParameters;
220//!
221//! let client_registration_finish_result = client_registration_start_result.state.finish(
222//!     &mut client_rng,
223//!     b"password",
224//!     server_registration_start_result.message,
225//!     ClientRegistrationFinishParameters::default(),
226//! )?;
227//! # Ok::<(), ProtocolError>(())
228//! ```
229//!
230//! ### Server Registration Finish
231//! In the fourth step of registration, the server takes as input a
232//! [`RegistrationUpload`] from the client, and a [`ServerRegistration`] from
233//! the second step. The server runs [`ServerRegistration::finish`] to produce a
234//! finalized [`ServerRegistration`]. At this point, the client can be
235//! considered as successfully registered, and the server can invoke
236//! [`ServerRegistration::serialize`] to store the password file for use during
237//! the login protocol.
238//! ```
239//! # use opaque_ke::{
240//! #   errors::ProtocolError,
241//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ServerSetup,
242//! #   ksf::Identity,
243//! # };
244//! # use opaque_ke::CipherSuite;
245//! # struct Default;
246//! # #[cfg(feature = "ristretto255")]
247//! # impl CipherSuite for Default {
248//! #     type OprfCs = opaque_ke::Ristretto255;
249//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
250//! #     type Ksf = opaque_ke::ksf::Identity;
251//! # }
252//! # #[cfg(not(feature = "ristretto255"))]
253//! # impl CipherSuite for Default {
254//! #     type OprfCs = p256::NistP256;
255//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
256//! #     type Ksf = opaque_ke::ksf::Identity;
257//! # }
258//! # use rand::{rngs::OsRng, RngCore};
259//! # let mut client_rng = OsRng;
260//! # let client_registration_start_result = ClientRegistration::<Default>::start(
261//! #     &mut client_rng,
262//! #     b"password",
263//! # )?;
264//! # let mut server_rng = OsRng;
265//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
266//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
267//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
268//! let password_file = ServerRegistration::<Default>::finish(
269//!     client_registration_finish_result.message,
270//! );
271//! # Ok::<(), ProtocolError>(())
272//! ```
273//!
274//! ## Login
275//! The login protocol between a client and server also consists of four steps
276//! along with three messages: [`CredentialRequest`], [`CredentialResponse`],
277//! [`CredentialFinalization`]. The server is expected to have access to the
278//! password file corresponding to an output of the registration phase (see
279//! [Dummy Server Login](#dummy-server-login) for handling the scenario where no
280//! password file is available). The login protocol will execute successfully
281//! only if the same password was used in the registration phase that produced
282//! the password file that the server is testing against.
283//!
284//! ### Client Login Start
285//! In the first step of login, the client chooses as input a login password.
286//! The client runs [`ClientLogin::start`] to produce an output consisting of a
287//! [`CredentialRequest`] to be sent to the server, and a [`ClientLogin`] which
288//! must be persisted on the client for the final step of client login.
289//! ```
290//! # use opaque_ke::{
291//! #   errors::ProtocolError,
292//! #   ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization,
293//! #   ksf::Identity,
294//! # };
295//! # use opaque_ke::CipherSuite;
296//! # struct Default;
297//! # #[cfg(feature = "ristretto255")]
298//! # impl CipherSuite for Default {
299//! #     type OprfCs = opaque_ke::Ristretto255;
300//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
301//! #     type Ksf = opaque_ke::ksf::Identity;
302//! # }
303//! # #[cfg(not(feature = "ristretto255"))]
304//! # impl CipherSuite for Default {
305//! #     type OprfCs = p256::NistP256;
306//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
307//! #     type Ksf = opaque_ke::ksf::Identity;
308//! # }
309//! # use rand::{rngs::OsRng, RngCore};
310//! use opaque_ke::ClientLogin;
311//!
312//! let mut client_rng = OsRng;
313//! let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"password")?;
314//! # Ok::<(), ProtocolError>(())
315//! ```
316//!
317//! ### Server Login Start
318//! In the second step of login, the server takes as input a persisted instance
319//! of [`ServerSetup`], the password file output from registration, a
320//! [`CredentialRequest`] from the client, and a server-side identifier for the
321//! client. The server runs [`ServerLogin::start`] to produce an output
322//! consisting of a [`CredentialResponse`] which is returned to the client, and
323//! a [`ServerLogin`] which must be persisted on the server for the final step
324//! of login.
325//! ```
326//! # use opaque_ke::{
327//! #   errors::ProtocolError,
328//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, ServerSetup,
329//! #   ksf::Identity,
330//! # };
331//! # use opaque_ke::CipherSuite;
332//! # struct Default;
333//! # #[cfg(feature = "ristretto255")]
334//! # impl CipherSuite for Default {
335//! #     type OprfCs = opaque_ke::Ristretto255;
336//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
337//! #     type Ksf = opaque_ke::ksf::Identity;
338//! # }
339//! # #[cfg(not(feature = "ristretto255"))]
340//! # impl CipherSuite for Default {
341//! #     type OprfCs = p256::NistP256;
342//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
343//! #     type Ksf = opaque_ke::ksf::Identity;
344//! # }
345//! # use rand::{rngs::OsRng, RngCore};
346//! # let mut client_rng = OsRng;
347//! # let client_registration_start_result = ClientRegistration::<Default>::start(
348//! #     &mut client_rng,
349//! #     b"password",
350//! # )?;
351//! # let mut server_rng = OsRng;
352//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
353//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
354//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
355//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
356//! # let client_login_start_result = ClientLogin::<Default>::start(
357//! #   &mut client_rng,
358//! #   b"password",
359//! # )?;
360//! use opaque_ke::{ServerLogin, ServerLoginParameters};
361//!
362//! let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
363//! let mut server_rng = OsRng;
364//! let server_login_start_result = ServerLogin::start(
365//!     &mut server_rng,
366//!     &server_setup,
367//!     Some(password_file),
368//!     client_login_start_result.message,
369//!     b"alice@example.com",
370//!     ServerLoginParameters::default(),
371//! )?;
372//! # Ok::<(), ProtocolError>(())
373//! ```
374//! Note that if there is no corresponding password file found for the user, the
375//! server can use `None` in place of `Some(password_file)` in order to generate
376//! a [`CredentialResponse`] that is indistinguishable from a valid
377//! [`CredentialResponse`] returned for a registered client. This allows the
378//! server to prevent leaking information about whether or not a client has
379//! previously registered with the server.
380//!
381//! ### Client Login Finish
382//! In the third step of login, the client takes as input a
383//! [`CredentialResponse`] from the server and runs [`ClientLogin::finish`]
384//! on it.
385//! If the authentication is successful, then the client obtains a
386//! [`ClientLoginFinishResult`]. Otherwise, on failure, the
387//! algorithm outputs an
388//! [`InvalidLoginError`](errors::ProtocolError::InvalidLoginError) error.
389//!
390//! The resulting [`ClientLoginFinishResult`] obtained by client in this step
391//! contains, among other things, a [`CredentialFinalization`] to be sent to the
392//! server to complete the protocol, and a
393//! [`session_key`](struct.ClientLoginFinishResult.html#structfield.session_key)
394//! which will match the server's session key upon a successful login.
395//! ```
396//! # use opaque_ke::{
397//! #   errors::ProtocolError,
398//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
399//! #   ksf::Identity,
400//! # };
401//! # use opaque_ke::CipherSuite;
402//! # struct Default;
403//! # #[cfg(feature = "ristretto255")]
404//! # impl CipherSuite for Default {
405//! #     type OprfCs = opaque_ke::Ristretto255;
406//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
407//! #     type Ksf = opaque_ke::ksf::Identity;
408//! # }
409//! # #[cfg(not(feature = "ristretto255"))]
410//! # impl CipherSuite for Default {
411//! #     type OprfCs = p256::NistP256;
412//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
413//! #     type Ksf = opaque_ke::ksf::Identity;
414//! # }
415//! # use rand::{rngs::OsRng, RngCore};
416//! # let mut client_rng = OsRng;
417//! # let client_registration_start_result = ClientRegistration::<Default>::start(
418//! #     &mut client_rng,
419//! #     b"password",
420//! # )?;
421//! # let mut server_rng = OsRng;
422//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
423//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
424//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
425//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
426//! # let client_login_start_result = ClientLogin::<Default>::start(
427//! #     &mut client_rng,
428//! #     b"password",
429//! # )?;
430//! # let password_file =
431//! #   ServerRegistration::<Default>::deserialize(
432//! #     &password_file_bytes,
433//! #   )?;
434//! # let server_login_start_result =
435//! #     ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"alice@example.com", ServerLoginParameters::default())?;
436//! use opaque_ke::ClientLoginFinishParameters;
437//!
438//! let client_login_finish_result = client_login_start_result.state.finish(
439//!     &mut client_rng,
440//!     b"password",
441//!     server_login_start_result.message,
442//!     ClientLoginFinishParameters::default(),
443//! )?;
444//! # Ok::<(), ProtocolError>(())
445//! ```
446//!
447//! ### Server Login Finish
448//! In the fourth step of login, the server takes as input a
449//! [`CredentialFinalization`] from the client and runs [`ServerLogin::finish`]
450//! to produce an output consisting of the `session_key` sequence of bytes which
451//! will match the client's session key upon a successful login.
452//! ```
453//! # use opaque_ke::{
454//! #   errors::ProtocolError,
455//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
456//! #   ksf::Identity,
457//! # };
458//! # use opaque_ke::CipherSuite;
459//! # struct Default;
460//! # #[cfg(feature = "ristretto255")]
461//! # impl CipherSuite for Default {
462//! #     type OprfCs = opaque_ke::Ristretto255;
463//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
464//! #     type Ksf = opaque_ke::ksf::Identity;
465//! # }
466//! # #[cfg(not(feature = "ristretto255"))]
467//! # impl CipherSuite for Default {
468//! #     type OprfCs = p256::NistP256;
469//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
470//! #     type Ksf = opaque_ke::ksf::Identity;
471//! # }
472//! # use rand::{rngs::OsRng, RngCore};
473//! # let mut client_rng = OsRng;
474//! # let client_registration_start_result = ClientRegistration::<Default>::start(
475//! #     &mut client_rng,
476//! #     b"password",
477//! # )?;
478//! # let mut server_rng = OsRng;
479//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
480//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
481//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
482//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
483//! # let client_login_start_result = ClientLogin::<Default>::start(
484//! #   &mut client_rng,
485//! #   b"password",
486//! # )?;
487//! # let password_file =
488//! #   ServerRegistration::<Default>::deserialize(
489//! #     &password_file_bytes,
490//! #   )?;
491//! # let server_login_start_result =
492//! #     ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"alice@example.com", ServerLoginParameters::default())?;
493//! # let client_login_finish_result = client_login_start_result.state.finish(
494//! #   &mut client_rng,
495//! #   b"password",
496//! #   server_login_start_result.message,
497//! #   ClientLoginFinishParameters::default(),
498//! # )?;
499//! let server_login_finish_result = server_login_start_result.state.finish(
500//!     client_login_finish_result.message,
501//!     ServerLoginParameters::default(),
502//! )?;
503//!
504//! assert_eq!(
505//!    client_login_finish_result.session_key,
506//!    server_login_finish_result.session_key,
507//! );
508//! # Ok::<(), ProtocolError>(())
509//! ```
510//! If the protocol completes successfully, then the server obtains a
511//! `server_login_finish_result.session_key` which is guaranteed to match
512//! `client_login_finish_result.session_key` (see the [Session
513//! Key](#session-key) section). Otherwise, on failure, the
514//! [`ServerLogin::finish`] algorithm outputs the error
515//! [`InvalidLoginError`](errors::ProtocolError::InvalidLoginError).
516//!
517//! # Advanced Usage
518//!
519//! This implementation offers support for several optional features of OPAQUE,
520//! described below. They are not critical to the execution of the main
521//! protocol, but can provide additional security benefits which can be suitable
522//! for various applications that rely on OPAQUE for authentication.
523//!
524//! ## Session Key
525//!
526//! Upon a successful completion of the OPAQUE protocol (the client runs login
527//! with the same password used during registration), the client and server have
528//! access to a session key, which is a pseudorandomly distributed byte
529//! string (of length equal to the output size of [`voprf::CipherSuite::Hash`])
530//! which only the client and server know. Multiple login runs using the
531//! same password for the same client will produce different session keys,
532//! distributed as uniformly random strings. Thus, the session key can be used
533//! to establish a secure channel between the client and server.
534//!
535//! The session key can be accessed from the `session_key` field of
536//! [`ClientLoginFinishResult`] and [`ServerLoginFinishResult`]. See the
537//! combination of [Client Login Finish](#client-login-finish) and [Server Login
538//! Finish](#server-login-finish) for example usage.
539//!
540//! ## Checking Server Consistency
541//!
542//! A [`ClientLoginFinishResult`] contains the `server_s_pk` field, which is
543//! represents the static public key of the server that is established during
544//! the setup phase. This can be used by the client to verify the authenticity
545//! of the server it engages with during the login phase. In particular, the
546//! client can check that the static public key of the server supplied during
547//! registration (with the `server_s_pk` field of
548//! [`ClientRegistrationFinishResult`]) matches this field during login.
549//! ```
550//! # use opaque_ke::{
551//! #   errors::ProtocolError,
552//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
553//! #   ksf::Identity,
554//! # };
555//! # use opaque_ke::CipherSuite;
556//! # struct Default;
557//! # #[cfg(feature = "ristretto255")]
558//! # impl CipherSuite for Default {
559//! #     type OprfCs = opaque_ke::Ristretto255;
560//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
561//! #     type Ksf = opaque_ke::ksf::Identity;
562//! # }
563//! # #[cfg(not(feature = "ristretto255"))]
564//! # impl CipherSuite for Default {
565//! #     type OprfCs = p256::NistP256;
566//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
567//! #     type Ksf = opaque_ke::ksf::Identity;
568//! # }
569//! # use rand::{rngs::OsRng, RngCore};
570//! # let mut client_rng = OsRng;
571//! # let client_registration_start_result = ClientRegistration::<Default>::start(
572//! #     &mut client_rng,
573//! #     b"password",
574//! # )?;
575//! # let mut server_rng = OsRng;
576//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
577//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
578//! // During registration, the client obtains a ClientRegistrationFinishResult with
579//! // a server_s_pk field
580//! let client_registration_finish_result = client_registration_start_result.state.finish(
581//!     &mut client_rng,
582//!     b"password",
583//!     server_registration_start_result.message,
584//!     ClientRegistrationFinishParameters::default(),
585//! )?;
586//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
587//! # let client_login_start_result = ClientLogin::<Default>::start(
588//! #     &mut client_rng,
589//! #     b"password",
590//! # )?;
591//! # let password_file =
592//! #   ServerRegistration::<Default>::deserialize(
593//! #     &password_file_bytes,
594//! #   )?;
595//! # let server_login_start_result =
596//! #     ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"alice@example.com", ServerLoginParameters::default())?;
597//!
598//! // And then later, during login...
599//! let client_login_finish_result = client_login_start_result.state.finish(
600//!     &mut client_rng,
601//!     b"password",
602//!     server_login_start_result.message,
603//!     ClientLoginFinishParameters::default(),
604//! )?;
605//!
606//! // Check that the server's static public key obtained from login matches what
607//! // was obtained during registration
608//! assert_eq!(
609//!     &client_registration_finish_result.server_s_pk,
610//!     &client_login_finish_result.server_s_pk,
611//! );
612//! # Ok::<(), ProtocolError>(())
613//! ```
614//!
615//! Note that without this check over the consistency of the server's static
616//! public key, a malicious actor could impersonate the registration server if
617//! it were able to copy the password file output during registration!
618//! Therefore, it is recommended to perform the following check in the
619//! application layer if the client can obtain a copy of the server's static
620//! public key beforehand.
621//!
622//!
623//! ## Export Key
624//!
625//! The export key is a pseudorandomly distributed byte string
626//! (of length equal to the output size of [`voprf::CipherSuite::Hash`]) output
627//! by both the [Client Registration Finish](#client-registration-finish) and
628//! [Client Login Finish](#client-login-finish) steps. The same export key
629//! string will be output by both functions only if the exact same password is
630//! passed to [`ClientRegistration::start`] and [`ClientLogin::start`].
631//!
632//! The export key retains as much secrecy as the password itself, and is
633//! similarly derived through an evaluation of the key stretching function.
634//! Hence, only the parties which know the password the client uses during
635//! registration and login can recover this secret, as it is never exposed to
636//! the server. As a result, the export key can be used (separately from the
637//! OPAQUE protocol) to provide confidentiality and integrity to other data
638//! which only the client should be able to process. For instance, if the server
639//! is expected to maintain any client-side secrets which require a password to
640//! access, then this export key can be used to encrypt these secrets so that
641//! they remain hidden from the server (see [examples/digital_locker.rs](https://github.com/facebook/opaque-ke/blob/main/examples/digital_locker.rs)
642//! for a working example).
643//!
644//! You can access the export key from the `export_key` field of
645//! [`ClientRegistrationFinishResult`] and [`ClientLoginFinishResult`].
646//! ```
647//! # use opaque_ke::{
648//! #   errors::ProtocolError,
649//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
650//! #   ksf::Identity,
651//! # };
652//! # use opaque_ke::CipherSuite;
653//! # struct Default;
654//! # #[cfg(feature = "ristretto255")]
655//! # impl CipherSuite for Default {
656//! #     type OprfCs = opaque_ke::Ristretto255;
657//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
658//! #     type Ksf = opaque_ke::ksf::Identity;
659//! # }
660//! # #[cfg(not(feature = "ristretto255"))]
661//! # impl CipherSuite for Default {
662//! #     type OprfCs = p256::NistP256;
663//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
664//! #     type Ksf = opaque_ke::ksf::Identity;
665//! # }
666//! # use rand::{rngs::OsRng, RngCore};
667//! # let mut client_rng = OsRng;
668//! # let client_registration_start_result = ClientRegistration::<Default>::start(
669//! #     &mut client_rng,
670//! #     b"password",
671//! # )?;
672//! # let mut server_rng = OsRng;
673//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
674//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
675//! // During registration...
676//! let client_registration_finish_result = client_registration_start_result.state.finish(
677//!     &mut client_rng,
678//!     b"password",
679//!     server_registration_start_result.message,
680//!     ClientRegistrationFinishParameters::default()
681//! )?;
682//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
683//! # let client_login_start_result = ClientLogin::<Default>::start(
684//! #     &mut client_rng,
685//! #     b"password",
686//! # )?;
687//! # let password_file =
688//! #   ServerRegistration::<Default>::deserialize(
689//! #     &password_file_bytes,
690//! #   )?;
691//! # let server_login_start_result =
692//! #     ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"alice@example.com", ServerLoginParameters::default())?;
693//!
694//! // And then later, during login...
695//! let client_login_finish_result = client_login_start_result.state.finish(
696//!     &mut client_rng,
697//!     b"password",
698//!     server_login_start_result.message,
699//!     ClientLoginFinishParameters::default(),
700//! )?;
701//!
702//! assert_eq!(
703//!     client_registration_finish_result.export_key,
704//!     client_login_finish_result.export_key,
705//! );
706//! # Ok::<(), ProtocolError>(())
707//! ```
708//!
709//! ## Custom Identifiers
710//!
711//! Typically when applications use OPAQUE to authenticate a client to a server,
712//! the client has a registered username which is sent to the server to identify
713//! the corresponding password file established during registration. This
714//! username may or may not coincide with the server-side identifier; however,
715//! this username must be known to both the client and the server (whereas the
716//! server-side identifier does not need to be exposed to the client). The
717//! server may also have an identifier corresponding to an entity (e.g.
718//! Facebook). By default, neither of these public identifiers need to be
719//! supplied to the OPAQUE protocol.
720//!
721//! But, for applications that wish to cryptographically bind these identities
722//! to the registered password file as well as the session key output by the
723//! login phase, these custom identifiers can be specified through
724//! [`ClientRegistrationFinishParameters`] in [Client Registration
725//! Finish](#client-registration-finish):
726//! ```
727//! # use opaque_ke::{
728//! #   errors::ProtocolError,
729//! #   ClientRegistration, ClientRegistrationFinishParameters, Identifiers, ServerRegistration, ServerSetup,
730//! #   ksf::Identity,
731//! # };
732//! # use opaque_ke::CipherSuite;
733//! # struct Default;
734//! # #[cfg(feature = "ristretto255")]
735//! # impl CipherSuite for Default {
736//! #     type OprfCs = opaque_ke::Ristretto255;
737//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
738//! #     type Ksf = opaque_ke::ksf::Identity;
739//! # }
740//! # #[cfg(not(feature = "ristretto255"))]
741//! # impl CipherSuite for Default {
742//! #     type OprfCs = p256::NistP256;
743//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
744//! #     type Ksf = opaque_ke::ksf::Identity;
745//! # }
746//! # use rand::{rngs::OsRng, RngCore};
747//! # let mut client_rng = OsRng;
748//! # let client_registration_start_result = ClientRegistration::<Default>::start(
749//! #     &mut client_rng,
750//! #     b"password",
751//! # )?;
752//! # let mut server_rng = OsRng;
753//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
754//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
755//! let client_registration_finish_result = client_registration_start_result.state.finish(
756//!     &mut client_rng,
757//!     b"password",
758//!     server_registration_start_result.message,
759//!     ClientRegistrationFinishParameters::new(
760//!         Identifiers {
761//!             client: Some(b"Alice_the_Cryptographer"),
762//!             server: Some(b"Facebook"),
763//!         },
764//!         None,
765//!     ),
766//! )?;
767//! # Ok::<(), ProtocolError>(())
768//! ```
769//!
770//! The same identifiers must also be supplied using [`ServerLoginParameters`]
771//! in [Server Login Start](#server-login-start):
772//! ```
773//! # use opaque_ke::{
774//! #   errors::ProtocolError,
775//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, Identifiers, ServerSetup,
776//! #   ksf::Identity,
777//! # };
778//! # use opaque_ke::CipherSuite;
779//! # struct Default;
780//! # #[cfg(feature = "ristretto255")]
781//! # impl CipherSuite for Default {
782//! #     type OprfCs = opaque_ke::Ristretto255;
783//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
784//! #     type Ksf = opaque_ke::ksf::Identity;
785//! # }
786//! # #[cfg(not(feature = "ristretto255"))]
787//! # impl CipherSuite for Default {
788//! #     type OprfCs = p256::NistP256;
789//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
790//! #     type Ksf = opaque_ke::ksf::Identity;
791//! # }
792//! # use rand::{rngs::OsRng, RngCore};
793//! # let mut client_rng = OsRng;
794//! # let client_registration_start_result = ClientRegistration::<Default>::start(
795//! #     &mut client_rng,
796//! #     b"password",
797//! # )?;
798//! # let mut server_rng = OsRng;
799//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
800//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
801//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
802//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
803//! # let client_login_start_result = ClientLogin::<Default>::start(
804//! #   &mut client_rng,
805//! #   b"password",
806//! # )?;
807//! # use opaque_ke::{ServerLogin, ServerLoginParameters};
808//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
809//! # let mut server_rng = OsRng;
810//! let server_login_start_result = ServerLogin::start(
811//!     &mut server_rng,
812//!     &server_setup,
813//!     Some(password_file),
814//!     client_login_start_result.message,
815//!     b"alice@example.com",
816//!     ServerLoginParameters {
817//!         context: None,
818//!         identifiers: Identifiers {
819//!             client: Some(b"Alice_the_Cryptographer"),
820//!             server: Some(b"Facebook"),
821//!         },
822//!     },
823//! )?;
824//! # Ok::<(), ProtocolError>(())
825//! ```
826//!
827//! as well as [`ClientLoginFinishParameters`] in [Client Login
828//! Finish](#client-login-finish):
829//! ```
830//! # use opaque_ke::{
831//! #   errors::ProtocolError,
832//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
833//! #   ksf::Identity,
834//! # };
835//! # use opaque_ke::CipherSuite;
836//! # struct Default;
837//! # #[cfg(feature = "ristretto255")]
838//! # impl CipherSuite for Default {
839//! #     type OprfCs = opaque_ke::Ristretto255;
840//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
841//! #     type Ksf = opaque_ke::ksf::Identity;
842//! # }
843//! # #[cfg(not(feature = "ristretto255"))]
844//! # impl CipherSuite for Default {
845//! #     type OprfCs = p256::NistP256;
846//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
847//! #     type Ksf = opaque_ke::ksf::Identity;
848//! # }
849//! # use rand::{rngs::OsRng, RngCore};
850//! # let mut client_rng = OsRng;
851//! # let client_registration_start_result = ClientRegistration::<Default>::start(
852//! #     &mut client_rng,
853//! #     b"password",
854//! # )?;
855//! # let mut server_rng = OsRng;
856//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
857//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
858//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
859//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
860//! # let client_login_start_result = ClientLogin::<Default>::start(
861//! #     &mut client_rng,
862//! #     b"password",
863//! # )?;
864//! # let password_file =
865//! #   ServerRegistration::<Default>::deserialize(
866//! #     &password_file_bytes,
867//! #   )?;
868//! # let server_login_start_result =
869//! #     ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"alice@example.com", ServerLoginParameters { context: None, identifiers: Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") } })?;
870//! let client_login_finish_result = client_login_start_result.state.finish(
871//!     &mut client_rng,
872//!     b"password",
873//!     server_login_start_result.message,
874//!     ClientLoginFinishParameters::new(
875//!         None,
876//!         Identifiers {
877//!             client: Some(b"Alice_the_Cryptographer"),
878//!             server: Some(b"Facebook"),
879//!         },
880//!         None,
881//!     ),
882//! )?;
883//!
884//! # Ok::<(), ProtocolError>(())
885//! ```
886//! and in [`ServerLoginParameters`] in [Server Login
887//! Finish](#server-login-finish):
888//! ```
889//! # use opaque_ke::{
890//! #   errors::ProtocolError,
891//! #   ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
892//! #   ksf::Identity,
893//! # };
894//! # use opaque_ke::CipherSuite;
895//! # struct Default;
896//! # #[cfg(feature = "ristretto255")]
897//! # impl CipherSuite for Default {
898//! #     type OprfCs = opaque_ke::Ristretto255;
899//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
900//! #     type Ksf = opaque_ke::ksf::Identity;
901//! # }
902//! # #[cfg(not(feature = "ristretto255"))]
903//! # impl CipherSuite for Default {
904//! #     type OprfCs = p256::NistP256;
905//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
906//! #     type Ksf = opaque_ke::ksf::Identity;
907//! # }
908//! # use rand::{rngs::OsRng, RngCore};
909//! # let mut client_rng = OsRng;
910//! # let client_registration_start_result = ClientRegistration::<Default>::start(
911//! #     &mut client_rng,
912//! #     b"password",
913//! # )?;
914//! # let mut server_rng = OsRng;
915//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
916//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
917//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
918//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
919//! # let client_login_start_result = ClientLogin::<Default>::start(
920//! #     &mut client_rng,
921//! #     b"password",
922//! # )?;
923//! # let password_file =
924//! #   ServerRegistration::<Default>::deserialize(
925//! #     &password_file_bytes,
926//! #   )?;
927//! # let server_login_start_result =
928//! #     ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"alice@example.com", ServerLoginParameters { context: None, identifiers: Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") } })?;
929//! # let client_login_finish_result = client_login_start_result.state.finish(
930//! #   &mut client_rng,
931//! #   b"password",
932//! #   server_login_start_result.message,
933//! #   ClientLoginFinishParameters::new(None, Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None),
934//! # )?;
935//! let server_login_finish_result = server_login_start_result.state.finish(
936//!     client_login_finish_result.message,
937//!     ServerLoginParameters { context: None, identifiers: Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") } },
938//! )?;
939//!
940//! # Ok::<(), ProtocolError>(())
941//! ```
942//! Failing to supply the same pair of custom identifiers in any of the three
943//! steps above will result in an error in attempting to complete the protocol!
944//!
945//! Note that if only one of the client and server identifiers are present, then
946//! [Identifiers] can be used to specify them individually.
947//!
948//! ## Key Exchange Context
949//!
950//! A key exchange protocol typically allows for the specifying of shared
951//! "context" information between the two parties before the exchange is
952//! complete, so as to bind the integrity of application-specific data or
953//! configuration parameters to the security of the key exchange. During the
954//! login phase, the client and server can specify this context using:
955//! - In [Server Login Start](#server-login-start), where the server can
956//!   populate [`ServerLoginParameters::context`].
957//! - In [Client Login Finish](#client-login-finish), where the client can
958//!   populate [`ClientLoginFinishParameters::context`].
959//! - In [Server Login Finish](#server-login-finish), where the server can
960//!   populate [`ServerLoginParameters::context`].
961//!
962//! ## Dummy Server Login
963//!
964//! For applications in which the server does not wish to reveal to the client
965//! whether an existing password file has been registered, the server can return
966//! a "dummy" credential response message to the client for an unregistered
967//! client, which is indistinguishable from the normal credential response
968//! message that the server would return for a registered client. The dummy
969//! message is created by passing a `None` to the `password_file` parameter for
970//! [`ServerLogin::start`].
971//!
972//! ## Remote Private Keys
973//!
974//! Servers that want to store their private key in an external location (e.g.
975//! in an HSM or vault) can do so with [`ServerLogin::builder()`] without
976//! exposing the bytes of the private key to this library.
977//! ```
978//! # use generic_array::{GenericArray, typenum::U0};
979//! # use opaque_ke::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
980//! # use rand::rngs::OsRng;
981//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
982//! # struct Default;
983//! # #[cfg(feature = "ristretto255")]
984//! # impl CipherSuite for Default {
985//! #     type OprfCs = opaque_ke::Ristretto255;
986//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
987//! #     type Ksf = opaque_ke::ksf::Identity;
988//! # }
989//! # #[cfg(not(feature = "ristretto255"))]
990//! # impl CipherSuite for Default {
991//! #     type OprfCs = p256::NistP256;
992//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
993//! #     type Ksf = opaque_ke::ksf::Identity;
994//! # }
995//! # #[derive(Debug, thiserror::Error)]
996//! # #[error("test error")]
997//! # struct YourRemoteKeyError;
998//! # #[derive(Clone)]
999//! # struct YourRemoteKey(<Ristretto255 as Group>::Sk);
1000//! # impl YourRemoteKey {
1001//! #     fn diffie_hellman(&self, pk: &PublicKey<Ristretto255>) -> Result<GenericArray<u8, <Ristretto255 as Group>::PkLen>, YourRemoteKeyError> {
1002//! #         Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type()))
1003//! #     }
1004//! # }
1005//! use opaque_ke::{ServerLogin, ServerLoginParameters, ServerSetup};
1006//! use opaque_ke::keypair::{KeyPair, PrivateKeySerialization};
1007//! use opaque_ke::errors::ProtocolError;
1008//!
1009//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
1010//! impl PrivateKeySerialization<Ristretto255> for YourRemoteKey {
1011//!     type Error = YourRemoteKeyError;
1012//!     type Len = U0;
1013//!
1014//!     fn serialize_key_pair(_: &KeyPair<Ristretto255, Self>) -> GenericArray<u8, Self::Len> {
1015//!         unimplemented!()
1016//!     }
1017//!
1018//!     fn deserialize_take_key_pair(input: &mut &[u8]) -> Result<KeyPair<Ristretto255, Self>, ProtocolError<Self::Error>> {
1019//!         unimplemented!()
1020//!     }
1021//! }
1022//!
1023//! # let sk = Ristretto255::random_sk(&mut OsRng);
1024//! # let pk = Ristretto255::public_key(&sk);
1025//! # let pk = Ristretto255::serialize_pk(&pk);
1026//! # let public_key = PublicKey::deserialize(&pk).unwrap();
1027//! # let remote_key = YourRemoteKey(sk);
1028//! # let mut server_rng = OsRng;
1029//! let keypair = KeyPair::new(remote_key, public_key);
1030//! let server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key_pair(&mut server_rng, keypair);
1031//!
1032//! # let client_registration_start_result = ClientRegistration::<Default>::start(
1033//! #     &mut OsRng,
1034//! #     b"password",
1035//! # )?;
1036//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?;
1037//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut OsRng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
1038//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
1039//! # let client_login_start_result = ClientLogin::<Default>::start(
1040//! #   &mut OsRng,
1041//! #   b"password",
1042//! # )?;
1043//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
1044//! // Use `ServerLogin::builder()` instead of `ServerLogin::start()`.
1045//! let server_login_builder = ServerLogin::builder(
1046//!     &mut server_rng,
1047//!     &server_setup,
1048//!     Some(password_file),
1049//!     client_login_start_result.message,
1050//!     b"alice@example.com",
1051//!     ServerLoginParameters::default(),
1052//! )?;
1053//!
1054//! // Run Diffie-Hellman on your remote key.
1055//! let client_e_public_key = server_login_builder.data();
1056//! let shared_secret = server_login_builder.private_key().diffie_hellman(&client_e_public_key)?;
1057//!
1058//! // Use the shared secret to build `ServerLogin`.
1059//! let server_login_start_result = server_login_builder.build(shared_secret)?;
1060//! # Ok::<(), anyhow::Error>(())
1061//! ```
1062//!
1063//! ## Remote OPRF Seeds
1064//!
1065//! In addition, the OPRF seed can be stored in an external location as well, by
1066//! using [`ServerRegistration::start_with_key_material()`] and
1067//! [`ServerLogin::builder_with_key_material()`] in combination with
1068//! [`ServerSetup::key_material_info()`].
1069//! ```
1070//! # use digest::Output;
1071//! # use generic_array::{GenericArray, typenum::U0};
1072//! # use hkdf::Hkdf;
1073//! # use opaque_ke::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
1074//! # use rand::rngs::OsRng;
1075//! # use rand::RngCore;
1076//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
1077//! # type Hash = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Hash;
1078//! # type OprfGroup = <<Default as CipherSuite>::OprfCs as voprf::CipherSuite>::Group;
1079//! # struct Default;
1080//! # #[cfg(feature = "ristretto255")]
1081//! # impl CipherSuite for Default {
1082//! #     type OprfCs = opaque_ke::Ristretto255;
1083//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
1084//! #     type Ksf = opaque_ke::ksf::Identity;
1085//! # }
1086//! # #[cfg(not(feature = "ristretto255"))]
1087//! # impl CipherSuite for Default {
1088//! #     type OprfCs = p256::NistP256;
1089//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
1090//! #     type Ksf = opaque_ke::ksf::Identity;
1091//! # }
1092//! # #[derive(Debug, thiserror::Error)]
1093//! # #[error("test error")]
1094//! # struct YourRemoteSecretsError;
1095//! # #[derive(Clone)]
1096//! # struct YourRemoteSeed(Output<Hash>);
1097//! # impl YourRemoteSeed {
1098//! #     fn hkdf(&self, info: &[&[u8]]) -> GenericArray<u8, <OprfGroup as voprf::Group>::ScalarLen> {
1099//! #         let mut ikm = GenericArray::default();
1100//! #         Hkdf::<Hash>::from_prk(&self.0)
1101//! #             .unwrap()
1102//! #             .expand_multi_info(info, &mut ikm)
1103//! #             .unwrap();
1104//! #         ikm
1105//! #     }
1106//! # }
1107//! # #[derive(Clone)]
1108//! # struct YourRemoteKey(<Ristretto255 as Group>::Sk);
1109//! # impl YourRemoteKey {
1110//! #     fn diffie_hellman(&self, pk: &PublicKey<Ristretto255>) -> Result<GenericArray<u8, <Ristretto255 as Group>::PkLen>, YourRemoteSecretsError> {
1111//! #         Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type()))
1112//! #     }
1113//! # }
1114//! use opaque_ke::{ServerLogin, ServerLoginParameters, ServerRegistration, ServerSetup};
1115//! use opaque_ke::keypair::{KeyPair, OprfSeedSerialization};
1116//! use opaque_ke::errors::ProtocolError;
1117//!
1118//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
1119//! impl OprfSeedSerialization<sha2::Sha512, YourRemoteSecretsError> for YourRemoteSeed {
1120//!     type Len = U0;
1121//!
1122//!     fn serialize(&self) -> GenericArray<u8, Self::Len> {
1123//!         unimplemented!()
1124//!     }
1125//!
1126//!     fn deserialize_take(input: &mut &[u8]) -> Result<YourRemoteSeed, ProtocolError<YourRemoteSecretsError>> {
1127//!         unimplemented!()
1128//!     }
1129//! }
1130//!
1131//! # let mut oprf_seed = YourRemoteSeed(GenericArray::default());
1132//! # OsRng.fill_bytes(&mut oprf_seed.0);
1133//! # let sk = Ristretto255::random_sk(&mut OsRng);
1134//! # let pk = Ristretto255::public_key(&sk);
1135//! # let pk = Ristretto255::serialize_pk(&pk);
1136//! # let public_key = PublicKey::deserialize(&pk).unwrap();
1137//! # let remote_key = YourRemoteKey(sk);
1138//! # let mut server_rng = OsRng;
1139//! let keypair = KeyPair::new(remote_key, public_key);
1140//! let server_setup = ServerSetup::<Default, YourRemoteKey, YourRemoteSeed>::new_with_key_pair_and_seed(&mut server_rng, keypair, oprf_seed);
1141//!
1142//! // Incoming registration ...
1143//! # let client_registration_start_result = ClientRegistration::<Default>::start(
1144//! #     &mut OsRng,
1145//! #     b"password",
1146//! # )?;
1147//!
1148//! // Run HKDF on your remote OPRF seed.
1149//! let info = server_setup.key_material_info(b"alice@example.com");
1150//! let key_material = info.ikm.hkdf(&info.info);
1151//!
1152//! // Use `ServerRegistration::start_with_key_material()` instead of `ServerRegistration::start()`.
1153//! let server_registration_start_result = ServerRegistration::<Default>::start_with_key_material(
1154//!     &server_setup,
1155//!     key_material,
1156//!     client_registration_start_result.message,
1157//! )?;
1158//!
1159//! // Finish registration ...
1160//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut OsRng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
1161//!
1162//! // Incoming login ...
1163//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
1164//! # let client_login_start_result = ClientLogin::<Default>::start(
1165//! #   &mut OsRng,
1166//! #   b"password",
1167//! # )?;
1168//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
1169//!
1170//! // Run HKDF on your remote OPRF seed.
1171//! let info = server_setup.key_material_info(b"alice@example.com");
1172//! let key_material = info.ikm.hkdf(&info.info);
1173//!
1174//! // Use `ServerLogin::builder_with_key_material()` instead of `ServerLogin::start()`.
1175//! let server_login_builder = ServerLogin::builder_with_key_material(
1176//!     &mut server_rng,
1177//!     &server_setup,
1178//!     key_material,
1179//!     Some(password_file),
1180//!     client_login_start_result.message,
1181//!     ServerLoginParameters::default(),
1182//! )?;
1183//!
1184//! // Run Diffie-Hellman on your remote key.
1185//! let client_e_public_key = server_login_builder.data();
1186//! let shared_secret = server_login_builder.private_key().diffie_hellman(&client_e_public_key)?;
1187//!
1188//! // Use the shared secret to build `ServerLogin`.
1189//! let server_login_start_result = server_login_builder.build(shared_secret)?;
1190//! # Ok::<(), anyhow::Error>(())
1191//! ```
1192//!
1193//! ## Custom KSF and Parameters
1194//!
1195//! An application might want to use a custom KSF (Key Stretching Function)
1196//! that's not supported directly by this crate. The maintainer of the said KSF
1197//! or of the application itself can implement the [`Ksf`](ksf::Ksf) trait to
1198//! use it with `opaque-ke`. `scrypt` is used for this example, but any KSF
1199//! can be used.
1200//! ```
1201//! # use generic_array::GenericArray;
1202//! use opaque_ke::ksf::Ksf;
1203//!
1204//! #[derive(Default)]
1205//! struct CustomKsf(scrypt::Params);
1206//!
1207//! // The Ksf trait must be implemented to be used in the ciphersuite.
1208//! impl Ksf for CustomKsf {
1209//!     fn hash<L: generic_array::ArrayLength<u8>>(
1210//!         &self,
1211//!         input: GenericArray<u8, L>,
1212//!     ) -> Result<GenericArray<u8, L>, opaque_ke::errors::InternalError> {
1213//!         let mut output = GenericArray::<u8, L>::default();
1214//!         scrypt::scrypt(&input, &[], &self.0, &mut output)
1215//!             .map_err(|_| opaque_ke::errors::InternalError::KsfError)?;
1216//!
1217//!         Ok(output)
1218//!     }
1219//! }
1220//! ```
1221//!
1222//! It is also possible to override the default derivation parameters that are
1223//! used by the KSF during registration and login. This can be especially
1224//! helpful if the `Ksf` trait is already implemented.
1225//! ```
1226//! # use opaque_ke::CipherSuite;
1227//! # use opaque_ke::ClientRegistration;
1228//! # use opaque_ke::ClientRegistrationFinishParameters;
1229//! # use opaque_ke::ServerSetup;
1230//! # use opaque_ke::errors::ProtocolError;
1231//! # use rand::rngs::OsRng;
1232//! # use rand::RngCore;
1233//! # use std::default::Default;
1234//! # #[cfg(feature = "argon2")]
1235//! # {
1236//! # struct DefaultCipherSuite;
1237//! # #[cfg(feature = "ristretto255")]
1238//! # impl CipherSuite for DefaultCipherSuite {
1239//! #     type OprfCs = opaque_ke::Ristretto255;
1240//! #     type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
1241//! #     type Ksf = argon2::Argon2<'static>;
1242//! # }
1243//! # #[cfg(not(feature = "ristretto255"))]
1244//! # impl CipherSuite for DefaultCipherSuite {
1245//! #     type OprfCs = p256::NistP256;
1246//! #     type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
1247//! #     type Ksf = argon2::Argon2<'static>;
1248//! # }
1249//! #
1250//! # let password = b"password";
1251//! # let mut rng = OsRng;
1252//! # let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
1253//! # let mut client_rng = OsRng;
1254//! # let client_registration_start_result =
1255//! #     ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password)?;
1256//! # use opaque_ke::ServerRegistration;
1257//! # let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start(
1258//! #     &server_setup,
1259//! #     client_registration_start_result.message,
1260//! #     b"alice@example.com",
1261//! # )?;
1262//! #
1263//! // Create an Argon2 instance with the specified parameters
1264//! let argon2_params = argon2::Params::new(131072, 2, 4, None).unwrap();
1265//! let argon2_params = argon2::Argon2::new(
1266//!     argon2::Algorithm::Argon2id,
1267//!     argon2::Version::V0x13,
1268//!     argon2_params,
1269//! );
1270//!
1271//! // Override the default parameters with the custom ones
1272//! let hash_params = ClientRegistrationFinishParameters {
1273//!     ksf: Some(&argon2_params),
1274//!     ..Default::default()
1275//! };
1276//!
1277//! let client_registration_finish_result = client_registration_start_result
1278//!     .state
1279//!     .finish(
1280//!         &mut rng,
1281//!         password,
1282//!         server_registration_start_result.message,
1283//!         hash_params,
1284//!     )
1285//!     .unwrap();
1286//! # }
1287//! # Ok::<(), ProtocolError>(())
1288//! ```
1289//!
1290//! # Features
1291//!
1292//! - The `argon2` feature, when enabled, introduces a dependency on `argon2`
1293//!   and implements the `Ksf` trait for `Argon2` with a set of default parameters.
1294//!   In general, secure instantiations should choose to invoke a memory-hard password
1295//!   hashing function when the client's password is expected to have low entropy,
1296//!   instead of relying on [`ksf::Identity`] as done in the above example. The
1297//!   more computationally intensive the `Ksf` function is, the more resistant
1298//!   the server's password file records will be against offline dictionary and precomputation
1299//!   attacks; see [the OPAQUE paper](https://eprint.iacr.org/2018/163.pdf) for
1300//!   more details. The `argon2` feature requires [`alloc`].
1301//!
1302//! - The `serde` feature, enabled by default, provides convenience functions for serializing and deserializing with [serde](https://serde.rs/).
1303//!
1304//! - The `ristretto255` feature enables using [`Ristretto255`] as a `KeGroup`
1305//!   and `OprfCs`. To select a specific backend see the [curve25519-dalek]
1306//!   documentation.
1307//!
1308//! - The `curve25519` feature enables Curve25519 as a `KeGroup`. To select a
1309//!   specific backend see the [curve25519-dalek] documentation.
1310//!
1311//! - The `ecdsa` feature enables using [`elliptic_curve`]s with [`Ecdsa`] for
1312//!   [`SigmaI`]s signature algorithm.
1313//!
1314//! - The `ed25519` feature enables using [`Ed25519`]s with [`PureEddsa`] and
1315//!   [`HashEddsa`] for [`SigmaI`]s signature algorithm.
1316//!
1317//! [`alloc`]: https://doc.rust-lang.org/alloc
1318//! [curve25519-dalek]: https://docs.rs/curve25519-dalek/4/curve25519_dalek/index.html#backends
1319
1320#![no_std]
1321#![cfg_attr(docsrs, feature(doc_cfg))]
1322#![cfg_attr(not(test), deny(unsafe_code))]
1323#![warn(clippy::cargo, clippy::doc_markdown, missing_docs, rustdoc::all)]
1324#![cfg_attr(not(test), warn(unused_crate_dependencies))]
1325#![allow(type_alias_bounds)]
1326
1327#[cfg(any(feature = "std", test))]
1328extern crate std;
1329
1330// Error types
1331pub mod errors;
1332
1333pub mod ciphersuite;
1334mod envelope;
1335pub mod hash;
1336pub mod key_exchange;
1337pub mod keypair;
1338pub mod ksf;
1339mod messages;
1340mod opaque;
1341mod serialization;
1342
1343#[cfg(test)]
1344mod tests;
1345
1346// Exports
1347
1348#[cfg(feature = "argon2")]
1349pub use argon2;
1350pub use {generic_array, rand};
1351
1352pub use crate::ciphersuite::CipherSuite;
1353#[cfg(feature = "curve25519")]
1354pub use crate::key_exchange::group::curve25519::Curve25519;
1355#[cfg(feature = "ed25519")]
1356pub use crate::key_exchange::group::ed25519::Ed25519;
1357#[cfg(feature = "ristretto255")]
1358pub use crate::key_exchange::group::ristretto255::Ristretto255;
1359pub use crate::key_exchange::sigma_i::SigmaI;
1360#[cfg(feature = "ecdsa")]
1361pub use crate::key_exchange::sigma_i::ecdsa::Ecdsa;
1362pub use crate::key_exchange::sigma_i::hash_eddsa::HashEddsa;
1363pub use crate::key_exchange::sigma_i::pure_eddsa::PureEddsa;
1364pub use crate::key_exchange::tripledh::TripleDh;
1365pub use crate::messages::{
1366    CredentialFinalization, CredentialFinalizationLen, CredentialRequest, CredentialRequestLen,
1367    CredentialResponse, CredentialResponseLen, RegistrationRequest, RegistrationRequestLen,
1368    RegistrationResponse, RegistrationResponseLen, RegistrationUpload, RegistrationUploadLen,
1369    ServerLoginBuilder,
1370};
1371pub use crate::opaque::{
1372    ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult, ClientLoginStartResult,
1373    ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationFinishResult,
1374    ClientRegistrationStartResult, Identifiers, KeyMaterialInfo, ServerLogin,
1375    ServerLoginFinishResult, ServerLoginParameters, ServerLoginStartResult, ServerRegistration,
1376    ServerRegistrationLen, ServerRegistrationStartResult, ServerSetup,
1377};