LCOV - differential code coverage report
Current view: top level - proxy/src/scram - password.rs (source / functions) Coverage Total Hit CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 100.0 % 40 40 40
Current Date: 2023-10-19 02:04:12 Functions: 100.0 % 7 7 7
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           TLA  Line data    Source code
       1                 : //! Password hashing routines.
       2                 : 
       3                 : use super::key::ScramKey;
       4                 : 
       5                 : pub const SALTED_PASSWORD_LEN: usize = 32;
       6                 : 
       7                 : /// Salted hashed password is essential for [key](super::key) derivation.
       8                 : #[repr(transparent)]
       9                 : pub struct SaltedPassword {
      10                 :     bytes: [u8; SALTED_PASSWORD_LEN],
      11                 : }
      12                 : 
      13                 : impl SaltedPassword {
      14                 :     /// See `scram-common.c : scram_SaltedPassword` for details.
      15                 :     /// Further reading: <https://datatracker.ietf.org/doc/html/rfc2898> (see `PBKDF2`).
      16 CBC           6 :     pub fn new(password: &[u8], salt: &[u8], iterations: u32) -> SaltedPassword {
      17               6 :         pbkdf2::pbkdf2_hmac_array::<sha2::Sha256, 32>(password, salt, iterations).into()
      18               6 :     }
      19                 : 
      20                 :     /// Derive `ClientKey` from a salted hashed password.
      21               5 :     pub fn client_key(&self) -> ScramKey {
      22               5 :         super::hmac_sha256(&self.bytes, [b"Client Key".as_ref()]).into()
      23               5 :     }
      24                 : 
      25                 :     /// Derive `ServerKey` from a salted hashed password.
      26               5 :     pub fn server_key(&self) -> ScramKey {
      27               5 :         super::hmac_sha256(&self.bytes, [b"Server Key".as_ref()]).into()
      28               5 :     }
      29                 : }
      30                 : 
      31                 : impl From<[u8; SALTED_PASSWORD_LEN]> for SaltedPassword {
      32                 :     #[inline(always)]
      33               7 :     fn from(bytes: [u8; SALTED_PASSWORD_LEN]) -> Self {
      34               7 :         Self { bytes }
      35               7 :     }
      36                 : }
      37                 : 
      38                 : #[cfg(test)]
      39                 : mod tests {
      40                 :     use super::SaltedPassword;
      41                 : 
      42               1 :     fn legacy_pbkdf2_impl(password: &[u8], salt: &[u8], iterations: u32) -> SaltedPassword {
      43               1 :         let one = 1_u32.to_be_bytes(); // magic
      44               1 : 
      45               1 :         let mut current = super::super::hmac_sha256(password, [salt, &one]);
      46               1 :         let mut result = current;
      47               1 :         for _ in 1..iterations {
      48            4095 :             current = super::super::hmac_sha256(password, [current.as_ref()]);
      49                 :             // TODO: result = current.zip(result).map(|(x, y)| x ^ y), issue #80094
      50          131040 :             for (i, x) in current.iter().enumerate() {
      51          131040 :                 result[i] ^= x;
      52          131040 :             }
      53                 :         }
      54                 : 
      55               1 :         result.into()
      56               1 :     }
      57                 : 
      58               1 :     #[test]
      59               1 :     fn pbkdf2() {
      60               1 :         let password = "a-very-secure-password";
      61               1 :         let salt = "such-a-random-salt";
      62               1 :         let iterations = 4096;
      63               1 :         let output = [
      64               1 :             203, 18, 206, 81, 4, 154, 193, 100, 147, 41, 211, 217, 177, 203, 69, 210, 194, 211,
      65               1 :             101, 1, 248, 156, 96, 0, 8, 223, 30, 87, 158, 41, 20, 42,
      66               1 :         ];
      67               1 : 
      68               1 :         let actual = SaltedPassword::new(password.as_bytes(), salt.as_bytes(), iterations);
      69               1 :         let expected = legacy_pbkdf2_impl(password.as_bytes(), salt.as_bytes(), iterations);
      70               1 : 
      71               1 :         assert_eq!(actual.bytes, output);
      72               1 :         assert_eq!(actual.bytes, expected.bytes);
      73               1 :     }
      74                 : }
        

Generated by: LCOV version 2.1-beta