LCOV - code coverage report
Current view: top level - proxy/src/scram - signature.rs (source / functions) Coverage Total Hit
Test: 32f4a56327bc9da697706839ed4836b2a00a408f.info Lines: 94.3 % 35 33
Test Date: 2024-02-07 07:37:29 Functions: 66.7 % 6 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            0 : #[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          101 :     pub fn build(&self, key: &ScramKey) -> Signature {
      15          101 :         let parts = [
      16          101 :             self.client_first_message_bare.as_bytes(),
      17          101 :             b",",
      18          101 :             self.server_first_message.as_bytes(),
      19          101 :             b",",
      20          101 :             self.client_final_message_without_proof.as_bytes(),
      21          101 :         ];
      22          101 : 
      23          101 :         super::hmac_sha256(key.as_ref(), parts).into()
      24          101 :     }
      25              : }
      26              : 
      27              : /// A computed value which, when xored with `ClientProof`,
      28              : /// produces `ClientKey` that we need for authentication.
      29            0 : #[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           53 :     pub fn derive_client_key(&self, proof: &[u8; SCRAM_KEY_LEN]) -> ScramKey {
      38           53 :         // This is how the proof is calculated:
      39           53 :         //
      40           53 :         // 1. sha256(ClientKey) -> StoredKey
      41           53 :         // 2. hmac_sha256(StoredKey, [messages...]) -> ClientSignature
      42           53 :         // 3. ClientKey ^ ClientSignature -> ClientProof
      43           53 :         //
      44           53 :         // Step 3 implies that we can restore ClientKey from the proof
      45           53 :         // by xoring the latter with the ClientSignature. Afterwards we
      46           53 :         // can check that the presumed ClientKey meets our expectations.
      47           53 :         let mut signature = self.bytes;
      48         1696 :         for (i, x) in proof.iter().enumerate() {
      49         1696 :             signature[i] ^= x;
      50         1696 :         }
      51              : 
      52           53 :         signature.into()
      53           53 :     }
      54              : }
      55              : 
      56              : impl From<[u8; SCRAM_KEY_LEN]> for Signature {
      57          101 :     fn from(bytes: [u8; SCRAM_KEY_LEN]) -> Self {
      58          101 :         Self { bytes }
      59          101 :     }
      60              : }
      61              : 
      62              : impl AsRef<[u8]> for Signature {
      63           48 :     fn as_ref(&self) -> &[u8] {
      64           48 :         &self.bytes
      65           48 :     }
      66              : }
        

Generated by: LCOV version 2.1-beta