3 releases (breaking)
0.3.0 | Aug 29, 2024 |
---|---|
0.2.0 | Aug 28, 2024 |
0.1.0 | Aug 26, 2024 |
#469 in Cryptography
34 downloads per month
33KB
455 lines
Wrapper crate for the srp
for easy usage
Overview
The 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.
- Easy to use.
Available rust/cargo features
client
: Include client classes (ClientAuthenticationWorkflow
,ClientRegistrationWorkflow
, ...).server
: Include server classes (ServerAuthenticationWorkflow
, etc.)base64
: Include the base64 crate and providebase64
serialization for various byte array parameters.serialization
: Include the serde crate and addSerialize
andDeserialize
to various structs. This also enables thebase64
feature.js
: This crate uses the getrandom crate for generating random numbers (salt, client/server ephemeral key).getrandom
supports a variety of platforms, including web browsers (in WebAssembly). Ifeasy-srp
is used inside the browser, use thejs
feature to makegetrandom
use theCrypto.getRandomValues()
JavaScript method for random number generation.
Usage
SRP6a protocol
User registration
- User enters
username
andpassword
- Client generates random
salt
- Client computes
verifier
from the above credentials - Client sends
username
,salt
andverifier
to the server via a secure channel. - Server stores these three credentials.
User authentication
Client | Server | |
---|---|---|
(username, pub_a) |
-> | |
<- | (salt, pub_b) |
|
(proof_a) |
-> | |
<- | (proof_b) |
- client generates ephemeral private key
a
and derices its public keypub_a
- client temporarily stores
a
for this authentication session. - client sends
(username, pub_a)
to the server. - server looks up
(salt, verifier)
forusername
. - server temporarily stores
pub_a
for this authentication session. - server computes an ephemeral private key
b
and derives its public keypub_b
. - server sends
(salt, pub_b)
to the client. - client calculates proof
proof_a
and sends(proof_a)
to the server. - server verifies
proof_a
- server computes its own proof
proof_b
and sends it to the client - client verifies
proof_b
- 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
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.
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.
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
- digest (also included transitively
via
srp
) - getrandom
- base64 (feature
base64
) - serde (feature
serde
)
Additional dependencies may be included transitively.
License
This project is licensed under the BSD-3-Clause license. See LICENSE.txt for the full license.
Dependencies
~1–1.6MB
~33K SLoC