5858//! ```
5959use std:: marker:: PhantomData ;
6060
61- use digest:: Digest ;
62- use generic_array:: GenericArray ;
61+ use digest:: { Digest , Output } ;
6362use num_bigint:: BigUint ;
6463
6564use crate :: tools:: powm;
@@ -77,29 +76,25 @@ pub struct SrpClient<'a, D: Digest> {
7776
7877/// SRP client state after handshake with the server.
7978pub struct SrpClientVerifier < D : Digest > {
80- proof : GenericArray < u8 , D :: OutputSize > ,
81- server_proof : GenericArray < u8 , D :: OutputSize > ,
82- key : GenericArray < u8 , D :: OutputSize > ,
79+ proof : Output < D > ,
80+ server_proof : Output < D > ,
81+ key : Output < D > ,
8382}
8483
8584/// Compute user private key as described in the RFC 5054. Consider using proper
8685/// password hashing algorithm instead.
87- pub fn srp_private_key < D : Digest > (
88- username : & [ u8 ] ,
89- password : & [ u8 ] ,
90- salt : & [ u8 ] ,
91- ) -> GenericArray < u8 , D :: OutputSize > {
86+ pub fn srp_private_key < D : Digest > ( username : & [ u8 ] , password : & [ u8 ] , salt : & [ u8 ] ) -> Output < D > {
9287 let p = {
9388 let mut d = D :: new ( ) ;
94- d. input ( username) ;
95- d. input ( b":" ) ;
96- d. input ( password) ;
97- d. result ( )
89+ d. update ( username) ;
90+ d. update ( b":" ) ;
91+ d. update ( password) ;
92+ d. finalize ( )
9893 } ;
9994 let mut d = D :: new ( ) ;
100- d. input ( salt) ;
101- d. input ( & p ) ;
102- d. result ( )
95+ d. update ( salt) ;
96+ d. update ( p . as_slice ( ) ) ;
97+ d. finalize ( )
10398}
10499
105100impl < ' a , D : Digest > SrpClient < ' a , D > {
@@ -123,12 +118,7 @@ impl<'a, D: Digest> SrpClient<'a, D> {
123118 v. to_bytes_be ( )
124119 }
125120
126- fn calc_key (
127- & self ,
128- b_pub : & BigUint ,
129- x : & BigUint ,
130- u : & BigUint ,
131- ) -> GenericArray < u8 , D :: OutputSize > {
121+ fn calc_key ( & self , b_pub : & BigUint , x : & BigUint , u : & BigUint ) -> Output < D > {
132122 let n = & self . params . n ;
133123 let k = self . params . compute_k :: < D > ( ) ;
134124 let interm = ( k * self . params . powm ( x) ) % n;
@@ -151,9 +141,10 @@ impl<'a, D: Digest> SrpClient<'a, D> {
151141 ) -> Result < SrpClientVerifier < D > , SrpAuthError > {
152142 let u = {
153143 let mut d = D :: new ( ) ;
154- d. input ( & self . a_pub . to_bytes_be ( ) ) ;
155- d. input ( b_pub) ;
156- BigUint :: from_bytes_be ( & d. result ( ) )
144+ d. update ( & self . a_pub . to_bytes_be ( ) ) ;
145+ d. update ( b_pub) ;
146+ let h = d. finalize ( ) ;
147+ BigUint :: from_bytes_be ( h. as_slice ( ) )
157148 } ;
158149
159150 let b_pub = BigUint :: from_bytes_be ( b_pub) ;
@@ -170,19 +161,79 @@ impl<'a, D: Digest> SrpClient<'a, D> {
170161 // M1 = H(A, B, K)
171162 let proof = {
172163 let mut d = D :: new ( ) ;
173- d. input ( & self . a_pub . to_bytes_be ( ) ) ;
174- d. input ( & b_pub. to_bytes_be ( ) ) ;
175- d. input ( & key) ;
176- d. result ( )
164+ d. update ( & self . a_pub . to_bytes_be ( ) ) ;
165+ d. update ( & b_pub. to_bytes_be ( ) ) ;
166+ d. update ( & key) ;
167+ d. finalize ( )
177168 } ;
178169
179170 // M2 = H(A, M1, K)
180171 let server_proof = {
181172 let mut d = D :: new ( ) ;
182- d. input ( & self . a_pub . to_bytes_be ( ) ) ;
183- d. input ( & proof) ;
184- d. input ( & key) ;
185- d. result ( )
173+ d. update ( & self . a_pub . to_bytes_be ( ) ) ;
174+ d. update ( & proof) ;
175+ d. update ( & key) ;
176+ d. finalize ( )
177+ } ;
178+
179+ Ok ( SrpClientVerifier {
180+ proof,
181+ server_proof,
182+ key,
183+ } )
184+ }
185+
186+ /// Process server reply to the handshake with username and salt.
187+ pub fn process_reply_with_username_and_salt (
188+ self ,
189+ username : & [ u8 ] ,
190+ salt : & [ u8 ] ,
191+ private_key : & [ u8 ] ,
192+ b_pub : & [ u8 ] ,
193+ ) -> Result < SrpClientVerifier < D > , SrpAuthError > {
194+ let u = {
195+ let mut d = D :: new ( ) ;
196+ d. update ( & self . a_pub . to_bytes_be ( ) ) ;
197+ d. update ( b_pub) ;
198+ let h = d. finalize ( ) ;
199+ BigUint :: from_bytes_be ( h. as_slice ( ) )
200+ } ;
201+
202+ let b_pub = BigUint :: from_bytes_be ( b_pub) ;
203+
204+ // Safeguard against malicious B
205+ if & b_pub % & self . params . n == BigUint :: default ( ) {
206+ return Err ( SrpAuthError {
207+ description : "Malicious b_pub value" ,
208+ } ) ;
209+ }
210+
211+ let x = BigUint :: from_bytes_be ( private_key) ;
212+ let key = self . calc_key ( & b_pub, & x, & u) ;
213+ // M1 = H(H(N)^H(g), H(I), salt, A, B, K)
214+ let proof = {
215+ let mut d = D :: new ( ) ;
216+ d. update ( username) ;
217+ let h = d. finalize_reset ( ) ;
218+ let I : & [ u8 ] = h. as_slice ( ) ;
219+
220+ d. update ( self . params . compute_hash_n_xor_hash_g :: < D > ( ) ) ;
221+ d. update ( I ) ;
222+ d. update ( salt) ;
223+ d. update ( & self . a_pub . to_bytes_be ( ) ) ;
224+ d. update ( & b_pub. to_bytes_be ( ) ) ;
225+ d. update ( & key. to_vec ( ) ) ;
226+ d. finalize ( )
227+ } ;
228+ let x = proof. to_vec ( ) . as_slice ( ) ;
229+
230+ // M2 = H(A, M1, K)
231+ let server_proof = {
232+ let mut d = D :: new ( ) ;
233+ d. update ( & self . a_pub . to_bytes_be ( ) ) ;
234+ d. update ( & proof) ;
235+ d. update ( & key) ;
236+ d. finalize ( )
186237 } ;
187238
188239 Ok ( SrpClientVerifier {
@@ -202,21 +253,18 @@ impl<D: Digest> SrpClientVerifier<D> {
202253 /// Get shared secret key without authenticating server, e.g. for using with
203254 /// authenticated encryption modes. DO NOT USE this method without
204255 /// some kind of secure authentication
205- pub fn get_key ( self ) -> GenericArray < u8 , D :: OutputSize > {
256+ pub fn get_key ( self ) -> Output < D > {
206257 self . key
207258 }
208259
209260 /// Verification data for sending to the server.
210- pub fn get_proof ( & self ) -> GenericArray < u8 , D :: OutputSize > {
261+ pub fn get_proof ( & self ) -> Output < D > {
211262 self . proof . clone ( )
212263 }
213264
214265 /// Verify server reply to verification data. It will return shared secret
215266 /// key in case of success.
216- pub fn verify_server (
217- self ,
218- reply : & [ u8 ] ,
219- ) -> Result < GenericArray < u8 , D :: OutputSize > , SrpAuthError > {
267+ pub fn verify_server ( self , reply : & [ u8 ] ) -> Result < Output < D > , SrpAuthError > {
220268 if self . server_proof . as_slice ( ) != reply {
221269 Err ( SrpAuthError {
222270 description : "Incorrect server proof" ,
0 commit comments