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 : }
|