srp6/
lib.rs

1//!
2//! # An implementation of Secure Remote Password (SRP6) authentication protocol.
3//!
4//! **NOTE**: Please do only use key length >= 2048 bit in production.
5//!           You can do so by using [`Srp6_2048`] or [`Srp6_4096`] or related.
6//!
7//! ## Usage
8//!
9//! The usage example start on the server side.
10//! Client side interaction is marked explicit when needed.
11//!
12//! ### 1. A new user, welcome Alice
13//!
14//! ```rust
15//! use srp6::prelude::*;
16//!
17//! // this is happening on the client,
18//! // the password is never send to the server at any time
19//! let new_username = Username::from("alice");
20//! let user_password = ClearTextPassword::from("password123");
21//!
22//! let (salt_s, verifier_v) = Srp6_4096::default()
23//!     .generate_new_user_secrets(
24//!         &new_username,
25//!         &user_password
26//!     );
27//!
28//! assert_eq!(salt_s.num_bytes(), Srp6_4096::KEY_LEN);
29//! assert_eq!(verifier_v.num_bytes(), Srp6_4096::KEY_LEN);
30//!
31//! // The server needs to persist,
32//! // `new_username`, `salt_s` and `verifier_v` in a user database / pw file
33//! ```
34//! **NOTE:** the password of the user will not be stored!
35//!
36//! **NOTE2:** the salt and verifier will never be the same, they have a random component to it
37//!
38//! ### 2. A session [`Handshake`] for Alice
39//!
40//! On the server side (when alice is already registered)
41//!
42//! - when a user/client connects they would send their [`Username`] first
43//! - with the username the server will lookup their [`Salt`] and [`PasswordVerifier`] from a user database or pw file
44//! - the server starts the authentication process with a [`Handshake`] send to the client
45//! - the server keeps a [`HandshakeProofVerifier`] for the user in order to verify the proof he will get from the client later on
46//!
47//! ```rust
48//! use srp6::prelude::*;
49//! #[path = "doc_test_mocks.rs"]
50//! mod mocks;
51//!
52//! // the username is sent by the client
53//! let user = mocks::lookup_user_details("alice");
54//!
55//! // the server starts the handshake
56//! let srp = Srp6_4096::default();
57//! let (handshake, proof_verifier) = srp.start_handshake(&user);
58//!
59//! assert_eq!(handshake.s, user.salt);
60//! assert_eq!(handshake.N, srp.N);
61//! assert_eq!(handshake.g, srp.g);
62//! assert_eq!(handshake.B.num_bytes(), Srp6_4096::KEY_LEN);
63//!
64//! // send `handshake` to the client
65//! // keep `proof_verifier` for later in a session or cache
66//! ```
67//!
68//! ### 3. A [`Proof`] that Alice is Alice
69//!
70//! - with the handshake, alice needs to create [`Proof`] that she is who she says she is
71//! - this [`Proof`] and her [`PublicKey`] will be sent to the server where it is verified
72//!
73//! ```rust
74//! use srp6::prelude::*;
75//! #[path = "doc_test_mocks.rs"]
76//! mod mocks;
77//!
78//! // this is entered by the user on the client (none is sent to the server)
79//! let username = "alice";
80//! let password = "password123";
81//!
82//! // this comes from the server
83//! let handshake = mocks::handshake_from_the_server(username);
84//!
85//! // the final proof calculation
86//! let (proof, strong_proof_verifier) = handshake
87//!     .calculate_proof(username, password)
88//!     .unwrap();
89//!
90//! // send this `proof` to the server
91//! // `strong_proof_verifier` is kept for the final verification
92//! ```
93//!
94//! ### 4. Verify [`Proof`] from Alice
95//!
96//! - The client sends the proof ([`HandshakeProof`]) to the server
97//! - The server calculates their version of the Proof and compoares if they match
98//! - On Success both parties have calculated a strong proof ([`StrongProof`] M2) and a session key ([`StrongSessionKey`] K)
99//!
100//! ```rust
101//! use srp6::prelude::*;
102//! #[path = "doc_test_mocks.rs"]
103//! mod mocks;
104//!
105//! // this comes from the server
106//! let username = "alice";
107//! let proof_verifier = mocks::stored_proof_verifier_from_step_2(username);
108//! let proof_from_alice = mocks::alice_proof();
109//!
110//! // the server verifies the proof from alice
111//! let (strong_proof, session_key_server) = proof_verifier
112//!     .verify_proof(&proof_from_alice)
113//!     .expect("proof was invalid");
114//!
115//! // `strong_proof` is sent back to alice
116//! ```
117//!
118//! ### 5. Alice verifies the server
119//!
120//! - The client receivs the strong proof ([`StrongProof`] K) from the server
121//! - Alice calculates their own strong proof and verifies the both match
122//! - On Success both parties have verified each other and have a shared strong proof ([`StrongProof`] M2) and a session key ([`StrongSessionKey`] K)
123//!
124//! ```rust
125//! use srp6::prelude::*;
126//! #[path = "doc_test_mocks.rs"]
127//! mod mocks;
128//!
129//! // see the previous step..
130//! let strong_proof_verifier = mocks::strong_proof_verifier_from_step_3();
131//! let strong_proof = mocks::strong_proof_from_the_server();
132//!
133//! // alice verifies the proof from the server
134//! strong_proof_verifier
135//!     .verify_strong_proof(&strong_proof)
136//!     .expect("strong proof was invalid");
137//! ```
138//!
139//! ## Note on key length
140//!
141//! this crate provides some default keys [preconfigured and aliased][defaults].
142//! The modulus prime and genrator numbers are taken from [RFC5054](https://datatracker.ietf.org/doc/html/rfc5054).
143//!
144//! ## Note on hash length
145//!
146//! The original RFC5054 uses SHA1 as the hash function. This crate uses SHA512 as the default hash function. Because SHA1 is considered weak, it is recommended to use newer versions of the SHA family. The hash length is 64 bytes for SHA512 instead of 20 bytes for SHA1. If you really need to use SHA1, you can use the `dangerous` feature.
147//!
148//! ## Further details and domain vocabolary
149//! - You can find the documentation of SRP6 [variables in a dedicated module][`protocol_details`].
150//! - [RFC2945](https://datatracker.ietf.org/doc/html/rfc2945) that describes in detail the Secure remote password protocol (SRP).
151//! - [RFC5054](https://datatracker.ietf.org/doc/html/rfc5054) that describes SRP6 for TLS Authentication
152//! - [check out the 2 examples](./examples) that illustrates the srp authentication flow as well
153
154pub mod defaults;
155pub mod hash;
156pub mod protocol_details;
157pub mod rfc_lingo;
158pub mod prelude {
159    pub use crate::api::host::*;
160    pub use crate::api::user::*;
161    pub use crate::big_number::BigNumber;
162    pub use crate::defaults::*;
163    pub use crate::error::Srp6Error;
164    pub use crate::hash::HASH_LENGTH;
165    pub use crate::primitives::*;
166    pub use std::convert::TryInto;
167}
168#[cfg(feature = "dangerous")]
169pub mod dangerous;
170pub mod rfc_5054_appendix_a;
171#[cfg(all(test, feature = "test-rfc-5054-appendix-b"))]
172pub mod rfc_5054_appendix_b;
173
174// #[cfg(any(test, doc, doctest, docsrs, feature = "doc-test-mocks"))]
175// pub mod doc_test_mocks;
176
177mod api;
178mod big_number;
179mod error;
180mod primitives;
181
182// // TODO: remove this, in favor of the prelude module
183// pub use api::host::*;
184// pub use api::user::*;
185// pub use defaults::*;
186// pub use primitives::{
187//     ClearTextPassword, Generator, MultiplierParameter, PasswordVerifier, PrimeModulus, PrivateKey,
188//     Proof, PublicKey, Salt, SessionKey, StrongProof, StrongSessionKey, UserCredentials,
189//     UserSecrets, Username, UsernameRef,
190// };
191// pub use std::convert::TryInto;
192
193/// encapsulates a [`crate::error::Srp6Error`]
194pub type Result<T> = std::result::Result<T, crate::error::Srp6Error>;
195
196pub use api::host::*;
197pub use api::user::*;
198pub use defaults::*;
199pub use primitives::*;