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