LCOV - code coverage report
Current view: top level - proxy/src/scram - signature.rs (source / functions) Coverage Total Hit
Test: 86c536b7fe84b2afe03c3bb264199e9c319ae0f8.info Lines: 100.0 % 33 33
Test Date: 2024-06-24 16:38:41 Functions: 100.0 % 4 4

            Line data    Source code
       1              : //! Tools for client/server signature management.
       2              : 
       3              : use super::key::{ScramKey, SCRAM_KEY_LEN};
       4              : 
       5              : /// A collection of message parts needed to derive the client's signature.
       6              : #[derive(Debug)]
       7              : pub struct SignatureBuilder<'a> {
       8              :     pub client_first_message_bare: &'a str,
       9              :     pub server_first_message: &'a str,
      10              :     pub client_final_message_without_proof: &'a str,
      11              : }
      12              : 
      13              : impl SignatureBuilder<'_> {
      14           30 :     pub fn build(&self, key: &ScramKey) -> Signature {
      15           30 :         let parts = [
      16           30 :             self.client_first_message_bare.as_bytes(),
      17           30 :             b",",
      18           30 :             self.server_first_message.as_bytes(),
      19           30 :             b",",
      20           30 :             self.client_final_message_without_proof.as_bytes(),
      21           30 :         ];
      22           30 : 
      23           30 :         super::hmac_sha256(key.as_ref(), parts).into()
      24           30 :     }
      25              : }
      26              : 
      27              : /// A computed value which, when xored with `ClientProof`,
      28              : /// produces `ClientKey` that we need for authentication.
      29              : #[derive(Debug)]
      30              : #[repr(transparent)]
      31              : pub struct Signature {
      32              :     bytes: [u8; SCRAM_KEY_LEN],
      33              : }
      34              : 
      35              : impl Signature {
      36              :     /// Derive `ClientKey` from client's signature and proof.
      37           16 :     pub fn derive_client_key(&self, proof: &[u8; SCRAM_KEY_LEN]) -> ScramKey {
      38           16 :         // This is how the proof is calculated:
      39           16 :         //
      40           16 :         // 1. sha256(ClientKey) -> StoredKey
      41           16 :         // 2. hmac_sha256(StoredKey, [messages...]) -> ClientSignature
      42           16 :         // 3. ClientKey ^ ClientSignature -> ClientProof
      43           16 :         //
      44           16 :         // Step 3 implies that we can restore ClientKey from the proof
      45           16 :         // by xoring the latter with the ClientSignature. Afterwards we
      46           16 :         // can check that the presumed ClientKey meets our expectations.
      47           16 :         let mut signature = self.bytes;
      48          512 :         for (i, x) in proof.iter().enumerate() {
      49          512 :             signature[i] ^= x;
      50          512 :         }
      51              : 
      52           16 :         signature.into()
      53           16 :     }
      54              : }
      55              : 
      56              : impl From<[u8; SCRAM_KEY_LEN]> for Signature {
      57           30 :     fn from(bytes: [u8; SCRAM_KEY_LEN]) -> Self {
      58           30 :         Self { bytes }
      59           30 :     }
      60              : }
      61              : 
      62              : impl AsRef<[u8]> for Signature {
      63           14 :     fn as_ref(&self) -> &[u8] {
      64           14 :         &self.bytes
      65           14 :     }
      66              : }
        

Generated by: LCOV version 2.1-beta