1use crypto::digest::Digest;
2use crypto::md5::Md5;
3use crypto::sha1::Sha1;
4
5pub struct CryptographicState {
8 pub(crate) alg: HashAlgorithm,
9 pub(crate) master_key: [u8; 48],
10 pub(crate) client_write_secret: Vec<u8>,
11 pub(crate) server_write_secret: Vec<u8>,
12 pub(crate) client_write_key: [u8; 16],
13 pub(crate) server_write_key: [u8; 16],
14}
15
16#[derive(Debug, Clone, Copy)]
17pub enum HashAlgorithm {
18 Md5,
19 Sha1,
20}
21
22impl HashAlgorithm {
23 pub fn hash_length(&self) -> usize {
25 match self {
26 Self::Md5 => 16,
27 Self::Sha1 => 20,
28 }
29 }
30
31 pub fn compare_mac(
34 &self,
35 mac: &[u8],
36 write_secret: &[u8],
37 ty: u8,
38 message: &[u8],
39 seq: &u64,
40 ) -> bool {
41 match self {
42 Self::Md5 => compute_mac_md5(write_secret, ty, message, seq).eq(mac),
43 Self::Sha1 => compute_mac_sha(write_secret, ty, message, seq).eq(mac),
44 }
45 }
46
47 pub fn append_mac(&self, payload: &mut Vec<u8>, write_secret: &[u8], ty: u8, seq: &u64) {
49 match self {
50 Self::Md5 => {
51 let mac = compute_mac_md5(write_secret, ty, &payload, seq);
52 payload.extend_from_slice(&mac);
53 }
54 Self::Sha1 => {
55 let mac = compute_mac_sha(write_secret, ty, &payload, seq);
56 payload.extend_from_slice(&mac);
57 }
58 }
59 }
60}
61
62pub fn create_crypto_state(
65 pm_key: &[u8],
66 alg: HashAlgorithm,
67 cr: &[u8; 32],
68 sr: &[u8; 32],
69) -> CryptographicState {
70 let mut master_key = [0u8; 48];
71 generate_key_block(&mut master_key, &pm_key, cr, sr);
72
73 let mut key_block = [0u8; 80];
75 generate_key_block(&mut key_block, &master_key, sr, cr);
76
77 let hash_length = alg.hash_length();
78 let (client_write_secret, key_block) = key_block.split_at(hash_length);
79 let (server_write_secret, key_block) = key_block.split_at(hash_length);
80
81 let mut client_write_key = [0u8; 16];
82 client_write_key.copy_from_slice(&key_block[0..16]);
83 let mut server_write_key = [0u8; 16];
84 server_write_key.copy_from_slice(&key_block[16..32]);
85
86 CryptographicState {
87 alg,
88 master_key,
89 client_write_secret: client_write_secret.to_vec(),
90 server_write_secret: server_write_secret.to_vec(),
91 client_write_key,
92 server_write_key,
93 }
94}
95
96pub fn generate_key_block(out: &mut [u8], pm: &[u8], rand_1: &[u8; 32], rand_2: &[u8; 32]) {
97 let mut outer = Md5::new();
99 let mut inner = Sha1::new();
101
102 let mut randoms = [0u8; 64];
103 randoms[..32].copy_from_slice(rand_1);
104 randoms[32..].copy_from_slice(rand_2);
105
106 let mut inner_value = [0u8; 20];
107
108 let salts = ["A", "BB", "CCC", "DDDD", "EEEEE"].iter();
109
110 for (chunk, salt) in out.chunks_mut(16).zip(salts) {
111 inner.input(salt.as_bytes());
112 inner.input(pm);
113 inner.input(&randoms);
114 inner.result(&mut inner_value);
115 inner.reset();
116
117 outer.input(pm);
118 outer.input(&inner_value);
119 outer.result(chunk);
120 outer.reset();
121 }
122}
123
124pub fn compute_mac_sha(write_secret: &[u8], ty: u8, message: &[u8], seq: &u64) -> [u8; 20] {
125 let mut digest = Sha1::new();
126 let mut out = [0u8; 20];
127 let pad1 = [0x36; 40];
128 let pad2 = [0x5c; 40];
129 digest.input(write_secret);
131 digest.input(&pad1);
132 digest.input(&seq.to_be_bytes());
133 digest.input(&[ty]);
134 let length = u16::to_be_bytes(message.len() as u16);
135 digest.input(&length);
136 digest.input(message);
137 digest.result(&mut out);
138 digest.reset();
139
140 digest.input(write_secret);
142 digest.input(&pad2);
143 digest.input(&out);
144 digest.result(&mut out);
145 out
146}
147
148pub fn compute_mac_md5(write_secret: &[u8], ty: u8, message: &[u8], seq: &u64) -> [u8; 16] {
149 let mut digest = Md5::new();
150 let mut out = [0u8; 16];
151 let pad1 = [0x36; 48];
152 let pad2 = [0x5c; 48];
153 digest.input(write_secret);
155 digest.input(&pad1);
156 digest.input(&seq.to_be_bytes());
157 digest.input(&[ty]);
158 let length = u16::to_be_bytes(message.len() as u16);
159 digest.input(&length);
160 digest.input(message);
161 digest.result(&mut out);
162 digest.reset();
163
164 digest.input(write_secret);
166 digest.input(&pad2);
167 digest.input(&out);
168 digest.result(&mut out);
169 out
170}
171
172pub enum FinishedSender {
173 Client,
174 Server,
175}
176
177impl FinishedSender {
178 pub fn value(&self) -> [u8; 4] {
179 let value: u32 = match self {
180 FinishedSender::Client => 0x434C4E54,
181 FinishedSender::Server => 0x53525652,
182 };
183 value.to_be_bytes()
184 }
185}
186
187pub fn compute_finished_md5(
188 master_secret: &[u8],
189 sender: &FinishedSender,
190 transcript: &[u8],
191) -> [u8; 16] {
192 let mut digest = Md5::new();
193 let mut out = [0u8; 16];
194 let pad1 = [0x36; 48];
195 let pad2 = [0x5c; 48];
196 digest.input(transcript);
197 digest.input(&sender.value());
198 digest.input(master_secret);
199 digest.input(&pad1);
200 digest.result(&mut out);
201 digest.reset();
202
203 digest.input(master_secret);
204 digest.input(&pad2);
205 digest.input(&out);
206 digest.result(&mut out);
207 out
208}
209
210pub fn compute_finished_sha(
211 master_secret: &[u8],
212 sender: &FinishedSender,
213 transcript: &[u8],
214) -> [u8; 20] {
215 let mut digest = Sha1::new();
216 let mut out = [0u8; 20];
217
218 let pad1 = [0x36; 40];
219 let pad2 = [0x5c; 40];
220 digest.input(transcript);
221 digest.input(&sender.value());
222 digest.input(master_secret);
223 digest.input(&pad1);
224 digest.result(&mut out);
225 digest.reset();
226
227 digest.input(master_secret);
228 digest.input(&pad2);
229 digest.input(&out);
230 digest.result(&mut out);
231 out
232}