@@ -114,7 +114,7 @@ pub fn hash_password_with_opts(
114114
115115/// Hashes a password using PBKDF2 with SHA256,
116116/// and returns it in the SCRAM-SHA-256 format.
117- /// The format is SCRAM-SHA-256$<iterations>:<salt>$<client_key >:<server_key>
117+ /// The format is SCRAM-SHA-256$<iterations>:<salt>$<stored_key >:<server_key>
118118pub fn scram256_hash ( password : & Password ) -> Result < String , HashError > {
119119 let hashed_password = hash_password ( password) ?;
120120 Ok ( scram256_hash_inner ( hashed_password) . to_string ( ) )
@@ -144,7 +144,7 @@ pub fn sasl_verify(
144144 proof : & str ,
145145 auth_message : & str ,
146146) -> Result < String , VerifyError > {
147- // Parse SCRAM hash: SCRAM-SHA-256$<iterations>:<salt>$<client_key >:<server_key>
147+ // Parse SCRAM hash: SCRAM-SHA-256$<iterations>:<salt>$<stored_key >:<server_key>
148148 let parts: Vec < & str > = hashed_password. split ( '$' ) . collect ( ) ;
149149 if parts. len ( ) != 3 {
150150 return Err ( VerifyError :: MalformedHash ) ;
@@ -158,39 +158,35 @@ pub fn sasl_verify(
158158 return Err ( VerifyError :: MalformedHash ) ;
159159 }
160160
161- let client_key = BASE64_STANDARD
161+ let stored_key = BASE64_STANDARD
162162 . decode ( auth_value[ 0 ] )
163163 . map_err ( |_| VerifyError :: MalformedHash ) ?;
164164 let server_key = BASE64_STANDARD
165165 . decode ( auth_value[ 1 ] )
166166 . map_err ( |_| VerifyError :: MalformedHash ) ?;
167167
168- // Compute stored key
169- let stored_key = openssl:: sha:: sha256 ( & client_key) ;
170-
171168 // Compute client signature: HMAC(stored_key, auth_message)
172169 let client_signature = generate_signature ( & stored_key, auth_message) ?;
173170
174- // Compute expected client proof: client_key XOR client_signature
175- let expected_client_proof: Vec < u8 > = client_key
176- . iter ( )
177- . zip_eq ( client_signature. iter ( ) )
178- . map ( |( a, b) | a ^ b)
179- . collect ( ) ;
180-
181171 // Decode provided proof
182172 let provided_client_proof = BASE64_STANDARD
183173 . decode ( proof)
184174 . map_err ( |_| VerifyError :: InvalidPassword ) ?;
185175
186- if constant_time_compare ( & expected_client_proof, & provided_client_proof) {
187- // Compute server verifier: HMAC(server_key, auth_message)
188- let verifier = generate_signature ( & server_key, auth_message) ?;
189- let verifier = BASE64_STANDARD . encode ( & verifier) ;
190- Ok ( verifier)
191- } else {
192- Err ( VerifyError :: InvalidPassword )
176+ // Recover client_key = proof XOR client_signature
177+ let client_key: Vec < u8 > = provided_client_proof
178+ . iter ( )
179+ . zip_eq ( client_signature. iter ( ) )
180+ . map ( |( p, s) | p ^ s)
181+ . collect ( ) ;
182+
183+ if !constant_time_compare ( & openssl:: sha:: sha256 ( & client_key) , & stored_key) {
184+ return Err ( VerifyError :: InvalidPassword ) ;
193185 }
186+
187+ // Compute server verifier: HMAC(server_key, auth_message)
188+ let verifier = generate_signature ( & server_key, auth_message) ?;
189+ Ok ( BASE64_STANDARD . encode ( & verifier) )
194190}
195191
196192fn generate_signature ( key : & [ u8 ] , message : & str ) -> Result < Vec < u8 > , VerifyError > {
@@ -267,7 +263,8 @@ struct ScramSha256Hash {
267263 /// The server key
268264 server_key : [ u8 ; SHA256_OUTPUT_LEN ] ,
269265 /// The client key
270- client_key : [ u8 ; SHA256_OUTPUT_LEN ] ,
266+ // client_key: [u8; SHA256_OUTPUT_LEN],
267+ stored_key : [ u8 ; SHA256_OUTPUT_LEN ] ,
271268}
272269
273270impl Display for ScramSha256Hash {
@@ -277,7 +274,7 @@ impl Display for ScramSha256Hash {
277274 "SCRAM-SHA-256${}:{}${}:{}" ,
278275 self . iterations,
279276 BASE64_STANDARD . encode( & self . salt) ,
280- BASE64_STANDARD . encode( & self . client_key ) ,
277+ BASE64_STANDARD . encode( & self . stored_key ) ,
281278 BASE64_STANDARD . encode( & self . server_key)
282279 )
283280 }
@@ -289,16 +286,18 @@ fn scram256_hash_inner(hashed_password: PasswordHash) -> ScramSha256Hash {
289286 openssl:: sign:: Signer :: new ( openssl:: hash:: MessageDigest :: sha256 ( ) , & signing_key) . unwrap ( ) ;
290287 signer. update ( b"Client Key" ) . unwrap ( ) ;
291288 let client_key = signer. sign_to_vec ( ) . unwrap ( ) ;
289+ let stored_key = openssl:: sha:: sha256 ( & client_key) ;
292290 let mut signer =
293291 openssl:: sign:: Signer :: new ( openssl:: hash:: MessageDigest :: sha256 ( ) , & signing_key) . unwrap ( ) ;
294292 signer. update ( b"Server Key" ) . unwrap ( ) ;
295- let server_key = signer. sign_to_vec ( ) . unwrap ( ) ;
293+ let mut server_key: [ u8 ; SHA256_OUTPUT_LEN ] = [ 0 ; SHA256_OUTPUT_LEN ] ;
294+ signer. sign ( server_key. as_mut ( ) ) . unwrap ( ) ;
296295
297296 ScramSha256Hash {
298297 iterations : hashed_password. iterations ,
299298 salt : hashed_password. salt ,
300- server_key : server_key . try_into ( ) . unwrap ( ) ,
301- client_key : client_key . try_into ( ) . unwrap ( ) ,
299+ server_key,
300+ stored_key ,
302301 }
303302}
304303
@@ -378,29 +377,41 @@ mod tests {
378377 let auth_message = "n=user,r=clientnonce,s=somesalt" ; // arbitrary auth message
379378
380379 // Parse client_key and server_key from the SCRAM hash
381- // Format: SCRAM-SHA-256$<iterations>:<salt>$<client_key >:<server_key>
380+ // Format: SCRAM-SHA-256$<iterations>:<salt>$<stored_key >:<server_key>
382381 let parts: Vec < & str > = hashed_password. split ( '$' ) . collect ( ) ;
383382 assert_eq ! ( parts. len( ) , 3 ) ;
384383 let key_parts: Vec < & str > = parts[ 2 ] . split ( ':' ) . collect ( ) ;
385384 assert_eq ! ( key_parts. len( ) , 2 ) ;
386- let client_key = BASE64_STANDARD
385+ let stored_key = BASE64_STANDARD
387386 . decode ( key_parts[ 0 ] )
388387 . expect ( "decode client key" ) ;
389388 let server_key = BASE64_STANDARD
390389 . decode ( key_parts[ 1 ] )
391390 . expect ( "decode server key" ) ;
392391
393- // stored_key = SHA256(client_key)
394- let stored_key = openssl:: sha:: sha256 ( & client_key) ;
395- // client_signature = HMAC(stored_key, auth_message)
396- let client_signature =
397- generate_signature ( & stored_key, auth_message) . expect ( "client signature" ) ;
398- // client_proof = client_key XOR client_signature
399- let client_proof: Vec < u8 > = client_key
400- . iter ( )
401- . zip_eq ( client_signature. iter ( ) )
402- . map ( |( a, b) | a ^ b)
403- . collect ( ) ;
392+ // Simulate client generating a proof
393+ let client_proof: Vec < u8 > = {
394+ // client_key = HMAC(salted_password, "Client Key")
395+ let opts = scram256_parse_opts ( & hashed_password) . expect ( "parse opts" ) ;
396+ let salted_password = hash_password_with_opts ( & opts, & password)
397+ . expect ( "hash password" )
398+ . hash ;
399+ let signing_key = openssl:: pkey:: PKey :: hmac ( & salted_password) . expect ( "signing key" ) ;
400+ let mut signer =
401+ openssl:: sign:: Signer :: new ( openssl:: hash:: MessageDigest :: sha256 ( ) , & signing_key)
402+ . expect ( "signer" ) ;
403+ signer. update ( b"Client Key" ) . expect ( "update" ) ;
404+ let client_key = signer. sign_to_vec ( ) . expect ( "client key" ) ;
405+ // client_proof = client_key XOR client_signature
406+ let client_signature =
407+ generate_signature ( & stored_key, auth_message) . expect ( "client signature" ) ;
408+ client_key
409+ . iter ( )
410+ . zip_eq ( client_signature. iter ( ) )
411+ . map ( |( c, s) | c ^ s)
412+ . collect :: < Vec < u8 > > ( )
413+ } ;
414+
404415 let client_proof_b64 = BASE64_STANDARD . encode ( & client_proof) ;
405416
406417 let verifier = sasl_verify ( & hashed_password, & client_proof_b64, auth_message)
0 commit comments