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(crate) struct SignatureBuilder<'a> {
8 : pub(crate) client_first_message_bare: &'a str,
9 : pub(crate) server_first_message: &'a str,
10 : pub(crate) client_final_message_without_proof: &'a str,
11 : }
12 :
13 : impl SignatureBuilder<'_> {
14 90 : pub(crate) fn build(&self, key: &ScramKey) -> Signature {
15 90 : let parts = [
16 90 : self.client_first_message_bare.as_bytes(),
17 90 : b",",
18 90 : self.server_first_message.as_bytes(),
19 90 : b",",
20 90 : self.client_final_message_without_proof.as_bytes(),
21 90 : ];
22 90 :
23 90 : super::hmac_sha256(key.as_ref(), parts).into()
24 90 : }
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(crate) struct Signature {
32 : bytes: [u8; SCRAM_KEY_LEN],
33 : }
34 :
35 : impl Signature {
36 : /// Derive `ClientKey` from client's signature and proof.
37 48 : pub(crate) fn derive_client_key(&self, proof: &[u8; SCRAM_KEY_LEN]) -> ScramKey {
38 48 : // This is how the proof is calculated:
39 48 : //
40 48 : // 1. sha256(ClientKey) -> StoredKey
41 48 : // 2. hmac_sha256(StoredKey, [messages...]) -> ClientSignature
42 48 : // 3. ClientKey ^ ClientSignature -> ClientProof
43 48 : //
44 48 : // Step 3 implies that we can restore ClientKey from the proof
45 48 : // by xoring the latter with the ClientSignature. Afterwards we
46 48 : // can check that the presumed ClientKey meets our expectations.
47 48 : let mut signature = self.bytes;
48 1536 : for (i, x) in proof.iter().enumerate() {
49 1536 : signature[i] ^= x;
50 1536 : }
51 :
52 48 : signature.into()
53 48 : }
54 : }
55 :
56 : impl From<[u8; SCRAM_KEY_LEN]> for Signature {
57 90 : fn from(bytes: [u8; SCRAM_KEY_LEN]) -> Self {
58 90 : Self { bytes }
59 90 : }
60 : }
61 :
62 : impl AsRef<[u8]> for Signature {
63 42 : fn as_ref(&self) -> &[u8] {
64 42 : &self.bytes
65 42 : }
66 : }
|