LCOV - code coverage report
Current view: top level - proxy/src/scram - key.rs (source / functions) Coverage Total Hit
Test: 1d5975439f3c9882b18414799141ebf9a3922c58.info Lines: 100.0 % 31 31
Test Date: 2025-07-31 15:59:03 Functions: 100.0 % 8 8

            Line data    Source code
       1              : //! Tools for client/server/stored key management.
       2              : 
       3              : use hmac::Mac as _;
       4              : use sha2::Digest as _;
       5              : use subtle::ConstantTimeEq;
       6              : use zeroize::Zeroize as _;
       7              : 
       8              : use crate::metrics::Metrics;
       9              : use crate::scram::pbkdf2::Prf;
      10              : 
      11              : /// Faithfully taken from PostgreSQL.
      12              : pub(crate) const SCRAM_KEY_LEN: usize = 32;
      13              : 
      14              : /// One of the keys derived from the user's password.
      15              : /// We use the same structure for all keys, i.e.
      16              : /// `ClientKey`, `StoredKey`, and `ServerKey`.
      17              : #[derive(Clone, Default, Eq, Debug)]
      18              : #[repr(transparent)]
      19              : pub(crate) struct ScramKey {
      20              :     bytes: [u8; SCRAM_KEY_LEN],
      21              : }
      22              : 
      23              : impl Drop for ScramKey {
      24          106 :     fn drop(&mut self) {
      25          106 :         self.bytes.zeroize();
      26          106 :     }
      27              : }
      28              : 
      29              : impl PartialEq for ScramKey {
      30            2 :     fn eq(&self, other: &Self) -> bool {
      31            2 :         self.ct_eq(other).into()
      32            2 :     }
      33              : }
      34              : 
      35              : impl ConstantTimeEq for ScramKey {
      36           18 :     fn ct_eq(&self, other: &Self) -> subtle::Choice {
      37           18 :         self.bytes.ct_eq(&other.bytes)
      38           18 :     }
      39              : }
      40              : 
      41              : impl ScramKey {
      42           16 :     pub(crate) fn sha256(&self) -> Self {
      43           16 :         Metrics::get().proxy.sha_rounds.inc_by(1);
      44           16 :         Self {
      45           16 :             bytes: sha2::Sha256::digest(self.as_bytes()).into(),
      46           16 :         }
      47           16 :     }
      48              : 
      49           23 :     pub(crate) fn as_bytes(&self) -> [u8; SCRAM_KEY_LEN] {
      50           23 :         self.bytes
      51           23 :     }
      52              : 
      53            8 :     pub(crate) fn client_key(b: &[u8; 32]) -> Self {
      54              :         // Prf::new_from_slice will run 2 sha256 rounds.
      55              :         // Update + Finalize run 2 sha256 rounds.
      56            8 :         Metrics::get().proxy.sha_rounds.inc_by(4);
      57              : 
      58            8 :         let mut prf = Prf::new_from_slice(b).expect("HMAC is able to accept all key sizes");
      59            8 :         prf.update(b"Client Key");
      60            8 :         let client_key: [u8; 32] = prf.finalize().into_bytes().into();
      61            8 :         client_key.into()
      62            8 :     }
      63              : }
      64              : 
      65              : impl From<[u8; SCRAM_KEY_LEN]> for ScramKey {
      66              :     #[inline(always)]
      67           54 :     fn from(bytes: [u8; SCRAM_KEY_LEN]) -> Self {
      68           54 :         Self { bytes }
      69           54 :     }
      70              : }
      71              : 
      72              : impl AsRef<[u8]> for ScramKey {
      73              :     #[inline(always)]
      74           17 :     fn as_ref(&self) -> &[u8] {
      75           17 :         &self.bytes
      76           17 :     }
      77              : }
        

Generated by: LCOV version 2.1-beta