11use crate :: connection:: stream:: PgStream ;
22use crate :: error:: Error ;
33use crate :: message:: { Authentication , AuthenticationSasl , SaslInitialResponse , SaslResponse } ;
4+ use crate :: rt;
45use crate :: PgConnectOptions ;
56use hmac:: { Hmac , Mac } ;
67use rand:: Rng ;
@@ -90,7 +91,8 @@ pub(crate) async fn authenticate(
9091 options. password . as_deref ( ) . unwrap_or_default ( ) ,
9192 & cont. salt ,
9293 cont. iterations ,
93- ) ?;
94+ )
95+ . await ?;
9496
9597 // ClientKey := HMAC(SaltedPassword, "Client Key")
9698 let mut mac = Hmac :: < Sha256 > :: new_from_slice ( & salted_password) . map_err ( Error :: protocol) ?;
@@ -187,7 +189,7 @@ fn gen_nonce() -> String {
187189}
188190
189191// Hi(str, salt, i):
190- fn hi < ' a > ( s : & ' a str , salt : & ' a [ u8 ] , iter_count : u32 ) -> Result < [ u8 ; 32 ] , Error > {
192+ async fn hi < ' a > ( s : & ' a str , salt : & ' a [ u8 ] , iter_count : u32 ) -> Result < [ u8 ; 32 ] , Error > {
191193 let mut mac = Hmac :: < Sha256 > :: new_from_slice ( s. as_bytes ( ) ) . map_err ( Error :: protocol) ?;
192194
193195 mac. update ( salt) ;
@@ -196,30 +198,19 @@ fn hi<'a>(s: &'a str, salt: &'a [u8], iter_count: u32) -> Result<[u8; 32], Error
196198 let mut u = mac. finalize_reset ( ) . into_bytes ( ) ;
197199 let mut hi = u;
198200
199- for _ in 1 ..iter_count {
201+ for i in 1 ..iter_count {
200202 mac. update ( u. as_slice ( ) ) ;
201203 u = mac. finalize_reset ( ) . into_bytes ( ) ;
202204 hi = hi. iter ( ) . zip ( u. iter ( ) ) . map ( |( & a, & b) | a ^ b) . collect ( ) ;
205+
206+ // For large iteration counts, this process can take a long time and block the event loop.
207+ // It was measured as taking ~50ms for 4096 iterations (the default) on a developer machine.
208+ // If we want to yield every 10-100us (as generally advised for tokio), then we can yield
209+ // every 5 iterations which should be every ~50us.
210+ if i % 5 == 0 {
211+ rt:: yield_now ( ) . await ;
212+ }
203213 }
204214
205215 Ok ( hi. into ( ) )
206216}
207-
208- #[ cfg( all( test, not( debug_assertions) ) ) ]
209- #[ bench]
210- fn bench_sasl_hi ( b : & mut test:: Bencher ) {
211- use test:: black_box;
212-
213- let mut rng = rand:: thread_rng ( ) ;
214- let nonce: Vec < u8 > = std:: iter:: repeat ( ( ) )
215- . map ( |( ) | rng. sample ( rand:: distributions:: Alphanumeric ) )
216- . take ( 64 )
217- . collect ( ) ;
218- b. iter ( || {
219- let _ = hi (
220- test:: black_box ( "secret_password" ) ,
221- test:: black_box ( & nonce) ,
222- test:: black_box ( 4096 ) ,
223- ) ;
224- } ) ;
225- }
0 commit comments