1
1
use crate :: connection:: stream:: PgStream ;
2
2
use crate :: error:: Error ;
3
3
use crate :: message:: { Authentication , AuthenticationSasl , SaslInitialResponse , SaslResponse } ;
4
+ use crate :: rt;
4
5
use crate :: PgConnectOptions ;
5
6
use hmac:: { Hmac , Mac } ;
6
7
use rand:: Rng ;
@@ -90,7 +91,8 @@ pub(crate) async fn authenticate(
90
91
options. password . as_deref ( ) . unwrap_or_default ( ) ,
91
92
& cont. salt ,
92
93
cont. iterations ,
93
- ) ?;
94
+ )
95
+ . await ?;
94
96
95
97
// ClientKey := HMAC(SaltedPassword, "Client Key")
96
98
let mut mac = Hmac :: < Sha256 > :: new_from_slice ( & salted_password) . map_err ( Error :: protocol) ?;
@@ -187,7 +189,7 @@ fn gen_nonce() -> String {
187
189
}
188
190
189
191
// 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 > {
191
193
let mut mac = Hmac :: < Sha256 > :: new_from_slice ( s. as_bytes ( ) ) . map_err ( Error :: protocol) ?;
192
194
193
195
mac. update ( salt) ;
@@ -196,30 +198,19 @@ fn hi<'a>(s: &'a str, salt: &'a [u8], iter_count: u32) -> Result<[u8; 32], Error
196
198
let mut u = mac. finalize_reset ( ) . into_bytes ( ) ;
197
199
let mut hi = u;
198
200
199
- for _ in 1 ..iter_count {
201
+ for i in 1 ..iter_count {
200
202
mac. update ( u. as_slice ( ) ) ;
201
203
u = mac. finalize_reset ( ) . into_bytes ( ) ;
202
204
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
+ }
203
213
}
204
214
205
215
Ok ( hi. into ( ) )
206
216
}
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