# Wrapper crate for the `srp` for easy usage ## Overview The [srp](https://crates.io/crates/srp) crate provides the means for using SRP6a athentication. This crate wraps the `srp` crate to make the authentication workflows more obvious easy to use. This is done via the following means: * provide `Workflow` structs for the 3 typical workflows: * generation of initial registration data * client authentication * server authentication * name methods `step#` with increasing number `#`, so it is obvious in which phase of the authentication the method needs to be called. * include automatic random value generation (for ephemeral keys and salt) ## Features * Support for the web via WebAssembly. Therefore, this crate can be used with WASM-based web-UI frameworks like [yew](https://crates.io/crates/yew). * Easy to use. ## Available rust/cargo `features` * `client`: Include client classes (`ClientAuthenticationWorkflow`, `ClientRegistrationWorkflow`, ...). * `server`: Include server classes (`ServerAuthenticationWorkflow`, etc.) * `base64`: Include the [base64](https://crates.io/crates/base64) crate and provide `base64` serialization for various byte array parameters. * `serialization`: Include the [serde](https://crates.io/crates/serde) crate and add `Serialize` and `Deserialize` to various structs. This also enables the `base64` feature. * `js`: This crate uses the [getrandom](https://crates.io/crates/getrandom) crate for generating random numbers (salt, client/server ephemeral key). `getrandom` supports a variety of platforms, including web browsers (in WebAssembly). If `easy-srp` is used inside the browser, use the `js` feature to make `getrandom` use the `Crypto.getRandomValues()` JavaScript method for random number generation. ## Usage ### SRP6a protocol #### User registration 1) User enters `username` and `password` 2) Client generates random `salt` 3) Client computes `verifier` from the above credentials 4) Client sends `username`, `salt` and `verifier` to the server via a secure channel. 5) Server stores these three credentials. #### User authentication | Client | | Server | | -------------------- | ---- | --------------------------- | | `(username, pub_a)` | -> | | | | <- | `(salt, pub_b)` | | `(proof_a)` | -> | | | | <- | `(proof_b)` | 1) client generates ephemeral private key `a` and derices its public key `pub_a` 2) client temporarily stores `a` for this authentication session. 3) client sends `(username, pub_a)` to the server. 4) server looks up `(salt, verifier)` for `username`. 5) server temporarily stores `pub_a` for this authentication session. 6) server computes an ephemeral private key `b` and derives its public key `pub_b`. 7) server sends `(salt, pub_b)` to the client. 8) client calculates proof `proof_a` and sends `(proof_a)` to the server. 9) server verifies `proof_a` 10) server computes its own proof `proof_b` and sends it to the client 11) client verifies `proof_b` 12) both sides are now able to calculate a common secret key. the size of the key depends on the used digest, e.g. 256 bits (32 bytes) for `SHA256` ### Generate client registration data ```rust use sha2::Sha256; use easy_srp::groups::G_4096; use easy_srp::client::{ClientRegistrationWorkflow, GenerateVerifierParams}; let verifier_wf = ClientRegistrationWorkflow::::new(&G_4096); let username = "lorem".to_string(); let password = "ipsum".to_string(); let verifier = verifier_wf.generate_verifier(GenerateVerifierParams { username: username.clone(), password: password.clone(), salt: None }).expect("could not generate verifier."); ``` ### Client example In this example, the `step#_on_server(...)` methods are just placeholders to show what data needs to be sent to the server and what data the server needs to reply with. ```rust use sha2::Sha256; use easy_srp::groups::G_4096; use easy_srp::client::{ClientAuthenticationWorkflow, ClientStep1Result, ClientStep3Result, ClientStep3Params} let username = "someuser"; let password = "somepassword"; let client_wf = crate::client::ClientAuthenticationWorkflow::::new(&G_4096); // compute ephemeral key of the client: let step1_result: ClientStep1Result = client_wf.step1().expect("could not compute step1"); // send username and step1_result.client_public_a to the server and get salt and server_public_a let (salt, server_public_b) = step2_on_server(username, step1_result.client_public_a); let step3_result: ClientStep3Result = client_wf.step3(ClientStep3Params { client_a: step1_result.client_private_a.as_slice(), username: username.clone(), password: password.clone(), salt, server_public_b }).expect("could not compute step3"); let server_proof = step4_on_server(step3_result.proof()); step3_result.verify_server(server_proof).expect("invalid server proof."); let key = step3_result.key(); ``` ### Server example In this example, the `step#_on_client(...)` methods are placeholders to show what data needs to be sent to/received from the client. The `retrieve_stored_credentials(username)` method is a placeholder to demonstrate that `salt` and `stored_verifier` (the verifier saved in the user registration process) need to be looked up given the username. ```rust use sha2::Sha256; use easy_srp::groups::G_4096; // receive username and client ephemeral public key from client let (username, client_public_a) = step1_on_client(); let (salt, stored_verifier) = retrieve_stored_credentials(username); let server_wf = crate::server::ServerAuthenticationWorkflow::::new(test_group); let step2_result: ServerStep2Result = server_wf.step2(ServerStep2Params { stored_verifier: verifier.verifier.as_slice() }).expect("could not compute step2"); let step4_result: ServerStep4Result = server_wf.step4(ServerStep4Params { client_public_a: step1_result.client_public_a.as_slice(), server_private_b: step2_result.server_private_b.as_slice(), stored_verifier: verifier.verifier.as_slice(), client_proof: step3_result.proof() }).expect("could not compute step4"); // verify the client proof before sending any encrypted data (including the // server proof) to the client. step4_result.verify_client(step3_result.proof()) .expect("could not verify client."); let key = step4_result.key(); ``` ## Dependencies The following dependencies are included intentionally (aka directly): * [srp](https://crates.io/crates/srp) * [digest](https://crates.io/crates/digest) (also included transitively via `srp`) * [getrandom](https://crates.io/crates/getrandom) * [base64](https://crates.io/crates/base64) (feature `base64`) * [serde](https://crates.io/crates/serde) (feature `serde`) Additional dependencies may be included transitively. ## License This project is licensed under the BSD-3-Clause license. See [LICENSE.txt](LICENSE.txt) for the full license.