# 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
| `(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::<Sha256>::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::<Sha256>::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<Sha256> = 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::<Sha256>::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<Sha256> = 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.