|
1 | 1 | use chacha20poly1305::{aead::generic_array::GenericArray, AeadInPlace, ChaCha20Poly1305, KeyInit}; |
| 2 | +use crypto_bigint::consts::U12; |
2 | 3 |
|
3 | 4 | use self::p2p_network_noise_state::ResponderConsumeOutput; |
4 | 5 |
|
5 | 6 | use super::*; |
6 | 7 |
|
7 | 8 | use super::p2p_network_noise_state::{ |
8 | | - NoiseError, NoiseState, P2pNetworkNoiseState, P2pNetworkNoiseStateInitiator, |
| 9 | + InitiatorOutput, NoiseError, NoiseState, P2pNetworkNoiseState, P2pNetworkNoiseStateInitiator, |
9 | 10 | P2pNetworkNoiseStateInner, P2pNetworkNoiseStateResponder, ResponderOutput, |
10 | 11 | }; |
11 | 12 |
|
| 13 | +const MAX_CHUNK_SIZE: usize = u16::MAX as usize - 19; |
| 14 | + |
12 | 15 | impl P2pNetworkNoiseState { |
13 | 16 | pub fn reducer(&mut self, action: redux::ActionWithMeta<&P2pNetworkNoiseAction>) { |
14 | 17 | match action.action() { |
@@ -68,13 +71,16 @@ impl P2pNetworkNoiseState { |
68 | 71 | let mut offset = 0; |
69 | 72 | loop { |
70 | 73 | let buf = &self.buffer[offset..]; |
71 | | - if buf.len() >= 2 { |
72 | | - let len = u16::from_be_bytes(buf[..2].try_into().expect("cannot fail")); |
| 74 | + // TODO: add bug_condition |
| 75 | + let len = buf |
| 76 | + .get(..2) |
| 77 | + .and_then(|buf| Some(u16::from_be_bytes(buf.try_into().ok()?))); |
| 78 | + |
| 79 | + if let Some(len) = len { |
73 | 80 | let full_len = 2 + len as usize; |
74 | 81 | if buf.len() >= full_len { |
75 | 82 | self.incoming_chunks.push_back(buf[..full_len].to_vec()); |
76 | 83 | offset += full_len; |
77 | | - |
78 | 84 | continue; |
79 | 85 | } |
80 | 86 | } |
@@ -187,56 +193,73 @@ impl P2pNetworkNoiseState { |
187 | 193 | .. |
188 | 194 | } => { |
189 | 195 | let aead = ChaCha20Poly1305::new(&send_key.0.into()); |
190 | | - let chunk_max_size = u16::MAX as usize - 19; |
191 | | - let chunks = data |
192 | | - .chunks(chunk_max_size) |
193 | | - .map(|data| { |
194 | | - let mut chunk = Vec::with_capacity(18 + data.len()); |
195 | | - chunk.extend_from_slice(&((data.len() + 16) as u16).to_be_bytes()); |
196 | | - chunk.extend_from_slice(data); |
| 196 | + let mut chunks = vec![]; |
| 197 | + |
| 198 | + for data_chunk in data.chunks(MAX_CHUNK_SIZE) { |
| 199 | + let mut chunk = Vec::with_capacity(18 + data_chunk.len()); |
| 200 | + chunk |
| 201 | + .extend_from_slice(&((data_chunk.len() + 16) as u16).to_be_bytes()); |
| 202 | + chunk.extend_from_slice(data_chunk); |
197 | 203 |
|
198 | | - let mut nonce = GenericArray::default(); |
199 | | - nonce[4..].clone_from_slice(&send_nonce.to_le_bytes()); |
200 | | - *send_nonce += 1; |
| 204 | + let mut nonce: GenericArray<u8, U12> = GenericArray::default(); |
| 205 | + nonce[4..].clone_from_slice(&send_nonce.to_le_bytes()); |
| 206 | + *send_nonce += 1; |
201 | 207 |
|
202 | | - let tag = aead |
203 | | - .encrypt_in_place_detached( |
204 | | - &nonce, |
205 | | - &[], |
206 | | - &mut chunk[2..(2 + data.len())], |
207 | | - ) |
208 | | - .expect("cannot fail"); |
209 | | - chunk.extend_from_slice(&tag); |
210 | | - chunk.into() |
211 | | - }) |
212 | | - .collect(); |
| 208 | + let tag = aead.encrypt_in_place_detached( |
| 209 | + &nonce, |
| 210 | + &[], |
| 211 | + &mut chunk[2..(2 + data_chunk.len())], |
| 212 | + ); |
| 213 | + |
| 214 | + let tag = match tag { |
| 215 | + Ok(tag) => tag, |
| 216 | + Err(_) => { |
| 217 | + *state = |
| 218 | + P2pNetworkNoiseStateInner::Error(NoiseError::Encryption); |
| 219 | + return; |
| 220 | + } |
| 221 | + }; |
| 222 | + |
| 223 | + chunk.extend_from_slice(&tag); |
| 224 | + chunks.push(chunk.into()); |
| 225 | + } |
213 | 226 | self.outgoing_chunks.push_back(chunks); |
214 | 227 | } |
215 | 228 | P2pNetworkNoiseStateInner::Initiator(i) => { |
216 | | - if let (Some((chunk, (send_key, recv_key))), Some(remote_pk)) = |
217 | | - (i.generate(data), i.remote_pk.clone()) |
218 | | - { |
219 | | - self.outgoing_chunks.push_back(vec![chunk.into()]); |
220 | | - let remote_peer_id = remote_pk.peer_id(); |
221 | | - |
222 | | - if self |
223 | | - .expected_peer_id |
224 | | - .is_some_and(|expected_per_id| expected_per_id != remote_peer_id) |
225 | | - { |
226 | | - *state = P2pNetworkNoiseStateInner::Error(dbg!( |
227 | | - NoiseError::RemotePeerIdMismatch |
228 | | - )); |
229 | | - } else { |
230 | | - *state = P2pNetworkNoiseStateInner::Done { |
231 | | - incoming: false, |
| 229 | + match (i.generate(data), i.remote_pk.clone()) { |
| 230 | + ( |
| 231 | + Ok(Some(InitiatorOutput { |
232 | 232 | send_key, |
233 | 233 | recv_key, |
234 | | - recv_nonce: 0, |
235 | | - send_nonce: 0, |
236 | | - remote_pk, |
237 | | - remote_peer_id, |
238 | | - }; |
| 234 | + chunk, |
| 235 | + })), |
| 236 | + Some(remote_pk), |
| 237 | + ) => { |
| 238 | + self.outgoing_chunks.push_back(vec![chunk.into()]); |
| 239 | + let remote_peer_id = remote_pk.peer_id(); |
| 240 | + |
| 241 | + if self.expected_peer_id.is_some_and(|expected_per_id| { |
| 242 | + expected_per_id != remote_peer_id |
| 243 | + }) { |
| 244 | + *state = P2pNetworkNoiseStateInner::Error(dbg!( |
| 245 | + NoiseError::RemotePeerIdMismatch |
| 246 | + )); |
| 247 | + } else { |
| 248 | + *state = P2pNetworkNoiseStateInner::Done { |
| 249 | + incoming: false, |
| 250 | + send_key, |
| 251 | + recv_key, |
| 252 | + recv_nonce: 0, |
| 253 | + send_nonce: 0, |
| 254 | + remote_pk, |
| 255 | + remote_peer_id, |
| 256 | + }; |
| 257 | + } |
| 258 | + } |
| 259 | + (Err(error), Some(_)) => { |
| 260 | + *state = P2pNetworkNoiseStateInner::Error(error); |
239 | 261 | } |
| 262 | + _ => (), |
240 | 263 | } |
241 | 264 | } |
242 | 265 | P2pNetworkNoiseStateInner::Responder(r) => { |
@@ -268,9 +291,17 @@ impl P2pNetworkNoiseState { |
268 | 291 | nonce[4..].clone_from_slice(&send_nonce.to_le_bytes()); |
269 | 292 | *send_nonce += 1; |
270 | 293 |
|
271 | | - let tag = aead |
272 | | - .encrypt_in_place_detached(&nonce, &[], &mut chunk[2..(2 + data.len())]) |
273 | | - .expect("cannot fail"); |
| 294 | + let tag = match aead.encrypt_in_place_detached( |
| 295 | + &nonce, |
| 296 | + &[], |
| 297 | + &mut chunk[2..(2 + data.len())], |
| 298 | + ) { |
| 299 | + Ok(tag) => tag, |
| 300 | + Err(_) => { |
| 301 | + self.inner = Some(P2pNetworkNoiseStateInner::Error(NoiseError::Encryption)); |
| 302 | + return; |
| 303 | + } |
| 304 | + }; |
274 | 305 | chunk.extend_from_slice(&tag); |
275 | 306 |
|
276 | 307 | self.outgoing_chunks.push_back(vec![chunk.into()]); |
|
0 commit comments