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