Crate srp6

Source
Expand description

§An implementation of Secure Remote Password (SRP6) authentication protocol.

NOTE: Please do only use key length >= 2048 bit in production. You can do so by using Srp6_2048 or Srp6_4096 or related.

§Usage

The usage example start on the server side. Client side interaction is marked explicit when needed.

§1. A new user, welcome Alice

use srp6::prelude::*;

// this is happening on the client,
// the password is never send to the server at any time
let new_username = Username::from("alice");
let user_password = ClearTextPassword::from("password123");

let (salt_s, verifier_v) = Srp6_4096::default()
    .generate_new_user_secrets(
        &new_username,
        &user_password
    );

assert_eq!(salt_s.num_bytes(), Srp6_4096::KEY_LEN);
assert_eq!(verifier_v.num_bytes(), Srp6_4096::KEY_LEN);

// The server needs to persist,
// `new_username`, `salt_s` and `verifier_v` in a user database / pw file

NOTE: the password of the user will not be stored!

NOTE2: the salt and verifier will never be the same, they have a random component to it

§2. A session Handshake for Alice

On the server side (when alice is already registered)

  • when a user/client connects they would send their Username first
  • with the username the server will lookup their Salt and PasswordVerifier from a user database or pw file
  • the server starts the authentication process with a Handshake send to the client
  • the server keeps a HandshakeProofVerifier for the user in order to verify the proof he will get from the client later on
use srp6::prelude::*;
#[path = "doc_test_mocks.rs"]
mod mocks;

// the username is sent by the client
let user = mocks::lookup_user_details("alice");

// the server starts the handshake
let srp = Srp6_4096::default();
let (handshake, proof_verifier) = srp.start_handshake(&user);

assert_eq!(handshake.s, user.salt);
assert_eq!(handshake.N, srp.N);
assert_eq!(handshake.g, srp.g);
assert_eq!(handshake.B.num_bytes(), Srp6_4096::KEY_LEN);

// send `handshake` to the client
// keep `proof_verifier` for later in a session or cache

§3. A Proof that Alice is Alice

  • with the handshake, alice needs to create Proof that she is who she says she is
  • this Proof and her PublicKey will be sent to the server where it is verified
use srp6::prelude::*;
#[path = "doc_test_mocks.rs"]
mod mocks;

// this is entered by the user on the client (none is sent to the server)
let username = "alice";
let password = "password123";

// this comes from the server
let handshake = mocks::handshake_from_the_server(username);

// the final proof calculation
let (proof, strong_proof_verifier) = handshake
    .calculate_proof(username, password)
    .unwrap();

// send this `proof` to the server
// `strong_proof_verifier` is kept for the final verification

§4. Verify Proof from Alice

  • The client sends the proof (HandshakeProof) to the server
  • The server calculates their version of the Proof and compoares if they match
  • On Success both parties have calculated a strong proof (StrongProof M2) and a session key (StrongSessionKey K)
use srp6::prelude::*;
#[path = "doc_test_mocks.rs"]
mod mocks;

// this comes from the server
let username = "alice";
let proof_verifier = mocks::stored_proof_verifier_from_step_2(username);
let proof_from_alice = mocks::alice_proof();

// the server verifies the proof from alice
let (strong_proof, session_key_server) = proof_verifier
    .verify_proof(&proof_from_alice)
    .expect("proof was invalid");

// `strong_proof` is sent back to alice

§5. Alice verifies the server

  • The client receivs the strong proof (StrongProof K) from the server
  • Alice calculates their own strong proof and verifies the both match
  • On Success both parties have verified each other and have a shared strong proof (StrongProof M2) and a session key (StrongSessionKey K)
use srp6::prelude::*;
#[path = "doc_test_mocks.rs"]
mod mocks;

// see the previous step..
let strong_proof_verifier = mocks::strong_proof_verifier_from_step_3();
let strong_proof = mocks::strong_proof_from_the_server();

// alice verifies the proof from the server
strong_proof_verifier
    .verify_strong_proof(&strong_proof)
    .expect("strong proof was invalid");

§Note on key length

this crate provides some default keys preconfigured and aliased. The modulus prime and genrator numbers are taken from RFC5054.

§Note on hash length

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.

§Further details and domain vocabolary

Re-exports§

pub use defaults::*;

Modules§

defaults
default prime modulus and generator numbers taken from RFC5054 Appendix A, so they can be treated as vetted and safe.
hash
prelude
protocol_details
A very brief summary of the papers and RFCs of SRP6 and SRP6a
rfc_5054_appendix_a
rfc_lingo

Structs§

Handshake
Contains all variables needed for a successful session key generation provided by the server to the client
HandshakeProof
Contains the client’s PublicKey and their Proof and is sent to the server
HandshakeProofVerifier
This is responsible for verifying a HandshakeProof that is provided by the client to the server
Srp6
Main interaction point for the server
StrongProofVerifier
Verifies the StrongProof provided by the server to the client
UserCredentials
Username and ClearTextPassword used on the client side
UserSecrets
User details composes Username, Salt and PasswordVerifier in one struct

Traits§

HostAPI
this trait provides a higher level api

Functions§

calculate_k
k = H(N | PAD(g)) (k = 3 for dangerous SRP-6)
calculate_p_hash
hashes the user and the password (used for client private key x)
calculate_password_verifier_v
here we calculate the PasswordVerifier called v based on x Note: something that only needs to be done on user pw change, or user creation x: Private key (derived from p and s) v: Password verifier g: A generator modulo N N: A large safe prime (N = 2q+1, where q is prime) formula: v = g^x % N
calculate_private_key_x
x is the users private key (only they know)
calculate_proof_M
calculate_pubkey_A
[../rfc_lingo::A] is the PublicKey of the client formula: A = g^a % N
calculate_pubkey_B
[PublicKey][../rfc_lingo::B] is the hosts public key B = kv + g^b
calculate_session_key_S_for_client
client version of the session key calculation, depends on
calculate_session_key_S_for_host
host version of a session key for a given user S: is the session key of a user u: is the hash of user and server pub keys
calculate_session_key_hash_interleave_K
the hash of a session key S that is called K S: is the session key of a user K: is the hash of S, just not that straight
calculate_strong_proof_M2
todo(verify): check if padding is needed or not formula: H(A | M | K)
calculate_u
[../rfc_lingo::u] is the hash of host’s [PublicKey][../rfc_lingo::A] and client’s [PublicKey][../rfc_lingo::B] formula: H(PAD(A) | PAD(B)) The Padding is based on the key length, e.g. if N is 1024 bit, the padding is 128 bytes
generate_private_key
PrivateKey a or b is in fact just a big (positive) random number
generate_salt
Salt s is a random number

Type Aliases§

ClearTextPassword
Clear text password p as str
ClearTextPasswordRef
Generator
Refers to the modulus generator g
KeyPair
A pair of PublicKey B and PrivateKey b
MultiplierParameter
Refers to a multiplier parameter k (k = H(N, g) in SRP-6a, k = 3 for dangerous SRP-6)
PasswordVerifier
Password Verifier is the users secret on the server side
PrimeModulus
Refers to a large safe prime called N (N = 2q+1, where q is prime)
PrivateKey
Refers to a private secret random number a (user), b (server)
Proof
Refers to M and M1 Proof of server and client
PublicKey
Refers to a Public shared key called A (user), B (server)
Result
encapsulates a crate::error::Srp6Error
Salt
Refers to a User’s salt called s
SessionKey
Refers to the SessionKey S
StrongProof
Refers to M2 the hash of Proof
StrongSessionKey
Refers to the StrongSessionKey K
Username
Username I as String
UsernameRef
Username reference I as &str