flashbang/message/attributes/
password_algorithms.rs1use bytes::Bytes;
2use md5::{Digest, Md5};
3use once_cell::unsync::Lazy;
4use sha2::Sha256;
5
6use super::*;
7
8pub struct PasswordAlgorithms {
14    algorithms: Vec<PasswordAlgorithm>,
15}
16
17impl Attribute for PasswordAlgorithms {
18    const TY: u16 = 0x8002;
19
20    const SIZE: usize = 0;
21
22    fn encode(&self, buf: &mut [u8], offset: usize) {
23        let mut i = 0;
24        for alg in &self.algorithms {
25            alg.encode(buf, offset + i);
26            i += (alg.size() + 3) & !3;
27        }
28    }
29
30    fn decode(buf: &[u8], meta: &AttributeMeta) -> Self {
31        let mut i = 0;
32        let mut algorithms = vec![];
33
34        while i != meta.len {
35            let offset = meta.offset + i;
36            let len = 4 + u16::from_be_bytes(buf[(offset + 2)..(offset + 4)].try_into().unwrap())
37                as usize;
38            let alg_meta = AttributeMeta {
39                ty: PasswordAlgorithm::TY,
40                offset,
41                len,
42            };
43
44            algorithms.push(PasswordAlgorithm::decode(buf, &alg_meta));
45
46            i += len;
47        }
48
49        Self { algorithms }
50    }
51
52    fn size(&self) -> usize {
53        let mut offset = 0;
54        for alg in &self.algorithms {
55            offset += (alg.size() + 3) & !3;
56        }
57
58        offset
59    }
60}
61
62#[derive(Clone)]
73pub struct PasswordAlgorithm {
74    id: u16,
75    algorithm: Box<dyn Algorithm>,
76}
77
78impl PartialEq for PasswordAlgorithm {
79    fn eq(&self, other: &Self) -> bool {
80        self.id == other.id
81    }
82}
83
84impl PasswordAlgorithm {
85    pub fn hash(&self, input: &[u8]) -> Bytes {
86        self.algorithm.hash(input)
87    }
88}
89
90impl Attribute for PasswordAlgorithm {
91    const TY: u16 = 0x001D;
92
93    const SIZE: usize = 0;
94
95    fn encode(&self, buf: &mut [u8], offset: usize) {
96        buf[offset..(offset + 2)].copy_from_slice(&self.id.to_be_bytes());
97
98        buf[(offset + 2)..(offset + 4)]
99            .copy_from_slice(&(self.algorithm.size() as u16).to_be_bytes());
100
101        self.algorithm.encode(buf, offset + 4);
102    }
103
104    fn decode(buf: &[u8], meta: &AttributeMeta) -> Self {
105        let id = u16::from_be_bytes(buf[meta.offset..(meta.offset + 2)].try_into().unwrap());
106
107        let len = u16::from_be_bytes(
108            buf[(meta.offset + 2)..(meta.offset + 4)]
109                .try_into()
110                .unwrap(),
111        );
112
113        let algorithm: Box<dyn Algorithm> = match id {
114            MD5_PASSWORD_ALGORITHM_TY => {
115                Box::new(Md5Algorithm::decode(buf, meta.offset, len as usize))
116            }
117            SHA256_PASSWORD_ALGORITHM_TY => {
118                Box::new(Sha256Algorithm::decode(buf, meta.offset, len as usize))
119            }
120            _ => panic!(),
121        };
122
123        Self { id, algorithm }
124    }
125
126    fn size(&self) -> usize {
127        4 + self.algorithm.size()
128    }
129}
130
131pub trait Algorithm: sealed::Sealed {
140    fn dyn_clone(&self) -> Box<dyn Algorithm>;
141
142    fn hash(&self, input: &[u8]) -> Bytes;
143
144    fn encode(&self, _buf: &mut [u8], _offset: usize) {}
145
146    fn decode(_buf: &[u8], _offset: usize, _len: usize) -> Self
147    where
148        Self: Sized;
149
150    fn size(&self) -> usize {
151        0
152    }
153}
154
155impl Clone for Box<dyn Algorithm> {
156    fn clone(&self) -> Self {
157        self.dyn_clone()
158    }
159}
160
161mod sealed {
162    pub trait Sealed {}
163    impl Sealed for super::Md5Algorithm {}
164    impl Sealed for super::Sha256Algorithm {}
165}
166
167const MD5_PASSWORD_ALGORITHM_TY: u16 = 0x0001;
168
169pub const MD5_PASSWORD_ALGORITHM: Lazy<PasswordAlgorithm> = Lazy::new(|| PasswordAlgorithm {
171    id: MD5_PASSWORD_ALGORITHM_TY,
172    algorithm: Box::new(Md5Algorithm),
173});
174
175#[derive(Default, Clone)]
176struct Md5Algorithm;
177
178impl Algorithm for Md5Algorithm {
179    fn dyn_clone(&self) -> Box<dyn Algorithm> {
180        Box::new(self.clone())
181    }
182
183    fn hash(&self, input: &[u8]) -> Bytes {
184        let mut hasher = Md5::new();
185
186        hasher.update(input);
187
188        let result = hasher.finalize();
189
190        Bytes::copy_from_slice(&*result)
191    }
192
193    fn decode(_buf: &[u8], _offset: usize, _len: usize) -> Self
194    where
195        Self: Sized,
196    {
197        Self::default()
198    }
199}
200
201const SHA256_PASSWORD_ALGORITHM_TY: u16 = 0x0002;
202
203pub const SHA256_PASSWORD_ALGORITHM: Lazy<PasswordAlgorithm> = Lazy::new(|| PasswordAlgorithm {
205    id: SHA256_PASSWORD_ALGORITHM_TY,
206    algorithm: Box::new(Sha256Algorithm),
207});
208
209#[derive(Default, Clone)]
210struct Sha256Algorithm;
211
212impl Algorithm for Sha256Algorithm {
213    fn dyn_clone(&self) -> Box<dyn Algorithm> {
214        Box::new(self.clone())
215    }
216
217    fn hash(&self, input: &[u8]) -> Bytes {
218        let mut hasher = Sha256::new();
219
220        hasher.update(input);
221
222        let result = hasher.finalize();
223
224        Bytes::copy_from_slice(&*result)
225    }
226
227    fn decode(_buf: &[u8], _offset: usize, _len: usize) -> Self
228    where
229        Self: Sized,
230    {
231        Self::default()
232    }
233}