srp/
server.rs

1//! SRP server implementation
2//!
3//! # Usage
4//! First receive user's username and public value `a_pub`, retrieve from a
5//! database the salt and verifier for a given username. Generate `b` and public value `b_pub`.
6//!
7//!
8//! ```rust
9//! use crate::srp::groups::G_2048;
10//! use sha2::Sha256; // Note: You should probably use a proper password KDF
11//! # use crate::srp::server::SrpServer;
12//! # fn get_client_request()-> (Vec<u8>, Vec<u8>) { (vec![], vec![])}
13//! # fn get_user(_: &[u8])-> (Vec<u8>, Vec<u8>) { (vec![], vec![])}
14//!
15//! let server = SrpServer::<Sha256>::new(&G_2048);
16//! let (username, a_pub) = get_client_request();
17//! let (salt, v) = get_user(&username);
18//! let mut b = [0u8; 64];
19//! // rng.fill_bytes(&mut b);
20//! let b_pub = server.compute_public_ephemeral(&b, &v);
21//! ```
22//!
23//! Next send to user `b_pub` and `salt` from user record
24//!
25//! Next process the user response:
26//!
27//! ```rust
28//! # let server = crate::srp::server::SrpServer::<sha2::Sha256>::new(&crate::srp::groups::G_2048);
29//! # fn get_client_response() -> Vec<u8> { vec![1] }
30//! # let b = [0u8; 64];
31//! # let v = b"";
32//!
33//! let a_pub = get_client_response();
34//! let verifier = server.process_reply(&b, v, &a_pub).unwrap();
35//! ```
36//!
37//!
38//! And finally receive user proof, verify it and send server proof in the
39//! reply:
40//!
41//! ```rust
42//! # let server = crate::srp::server::SrpServer::<sha2::Sha256>::new(&crate::srp::groups::G_2048);
43//! # let verifier = server.process_reply(b"", b"", b"1").unwrap();
44//! # fn get_client_proof()-> Vec<u8> { vec![26, 80, 8, 243, 111, 162, 238, 171, 208, 237, 207, 46, 46, 137, 44, 213, 105, 208, 84, 224, 244, 216, 103, 145, 14, 103, 182, 56, 242, 4, 179, 57] };
45//! # fn send_proof(_: &[u8]) { };
46//!
47//! let client_proof = get_client_proof();
48//! verifier.verify_client(&client_proof).unwrap();
49//! send_proof(verifier.proof());
50//! ```
51//!
52//!
53//! `key` contains shared secret key between user and the server. You can extract shared secret
54//! key using `key()` method.
55//! ```rust
56//! # let server = crate::srp::server::SrpServer::<sha2::Sha256>::new(&crate::srp::groups::G_2048);
57//! # let verifier = server.process_reply(b"", b"", b"1").unwrap();
58//!
59//! verifier.key();
60//!```
61//!
62use std::marker::PhantomData;
63
64use digest::{Digest, Output};
65use num_bigint::BigUint;
66use subtle::ConstantTimeEq;
67
68use crate::types::{SrpAuthError, SrpGroup};
69use crate::utils::{compute_k, compute_m1, compute_m2, compute_u};
70
71/// SRP server state
72pub struct SrpServer<'a, D: Digest> {
73    params: &'a SrpGroup,
74    d: PhantomData<D>,
75}
76
77/// SRP server state after handshake with the client.
78pub struct SrpServerVerifier<D: Digest> {
79    m1: Output<D>,
80    m2: Output<D>,
81    key: Vec<u8>,
82}
83
84impl<'a, D: Digest> SrpServer<'a, D> {
85    /// Create new server state.
86    pub fn new(params: &'a SrpGroup) -> Self {
87        Self {
88            params,
89            d: Default::default(),
90        }
91    }
92
93    //  k*v + g^b % N
94    pub fn compute_b_pub(&self, b: &BigUint, k: &BigUint, v: &BigUint) -> BigUint {
95        let inter = (k * v) % &self.params.n;
96        (inter + self.params.g.modpow(b, &self.params.n)) % &self.params.n
97    }
98
99    // <premaster secret> = (A * v^u) ^ b % N
100    pub fn compute_premaster_secret(
101        &self,
102        a_pub: &BigUint,
103        v: &BigUint,
104        u: &BigUint,
105        b: &BigUint,
106    ) -> BigUint {
107        // (A * v^u)
108        let base = (a_pub * v.modpow(u, &self.params.n)) % &self.params.n;
109        base.modpow(b, &self.params.n)
110    }
111
112    /// Get public ephemeral value for sending to the client.
113    pub fn compute_public_ephemeral(&self, b: &[u8], v: &[u8]) -> Vec<u8> {
114        self.compute_b_pub(
115            &BigUint::from_bytes_be(b),
116            &compute_k::<D>(self.params),
117            &BigUint::from_bytes_be(v),
118        )
119        .to_bytes_be()
120    }
121
122    /// Process client reply to the handshake.
123    /// b is a random value,
124    /// v is the provided during initial user registration
125    pub fn process_reply(
126        &self,
127        b: &[u8],
128        v: &[u8],
129        a_pub: &[u8],
130    ) -> Result<SrpServerVerifier<D>, SrpAuthError> {
131        let b = BigUint::from_bytes_be(b);
132        let v = BigUint::from_bytes_be(v);
133        let a_pub = BigUint::from_bytes_be(a_pub);
134
135        let k = compute_k::<D>(self.params);
136        let b_pub = self.compute_b_pub(&b, &k, &v);
137
138        // Safeguard against malicious A
139        if &a_pub % &self.params.n == BigUint::default() {
140            return Err(SrpAuthError::IllegalParameter("a_pub".to_owned()));
141        }
142
143        let u = compute_u::<D>(&a_pub.to_bytes_be(), &b_pub.to_bytes_be());
144
145        let key = self.compute_premaster_secret(&a_pub, &v, &u, &b);
146
147        let m1 = compute_m1::<D>(
148            &a_pub.to_bytes_be(),
149            &b_pub.to_bytes_be(),
150            &key.to_bytes_be(),
151        );
152
153        let m2 = compute_m2::<D>(&a_pub.to_bytes_be(), &m1, &key.to_bytes_be());
154
155        Ok(SrpServerVerifier {
156            m1,
157            m2,
158            key: key.to_bytes_be(),
159        })
160    }
161}
162
163impl<D: Digest> SrpServerVerifier<D> {
164    /// Get shared secret between user and the server. (do not forget to verify
165    /// that keys are the same!)
166    pub fn key(&self) -> &[u8] {
167        &self.key
168    }
169
170    /// Verification data for sending to the client.
171    pub fn proof(&self) -> &[u8] {
172        // TODO not Output
173        self.m2.as_slice()
174    }
175
176    /// Process user proof of having the same shared secret.
177    pub fn verify_client(&self, reply: &[u8]) -> Result<(), SrpAuthError> {
178        if self.m1.ct_eq(reply).unwrap_u8() != 1 {
179            // aka == 0
180            Err(SrpAuthError::BadRecordMac("client".to_owned()))
181        } else {
182            Ok(())
183        }
184    }
185}