1use aead_stream::{Decryptor, NonceSize, StreamPrimitive};
2use chacha20poly1305::aead::{array::ArraySize, AeadInOut};
3use pin_project_lite::pin_project;
4use std::{ops::Sub, pin::Pin, task::ready};
5
6use tokio::io::{AsyncBufRead, AsyncRead};
7
8use crate::DEFAULT_BUFFER_SIZE;
9
10pin_project! {
11 pub struct ReadHalf<T, U> {
13
14 #[pin]
15 inner: T,
16 decryptor: U,
17 buffer: Vec<u8>,
18 pos: usize,
19 cap: usize,
20
21 overflow: Vec<u8>
24 }
25}
26
27impl<T, A, S> ReadHalf<T, Decryptor<A, S>>
28where
29 S: StreamPrimitive<A>,
30 A: AeadInOut,
31 A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
32 NonceSize<A, S>: ArraySize,
33{
34 pub fn new(inner: T, decryptor: Decryptor<A, S>) -> Self {
35 Self::with_capacity(inner, decryptor, DEFAULT_BUFFER_SIZE)
36 }
37 pub fn with_capacity(inner: T, decryptor: Decryptor<A, S>, size: usize) -> Self {
38 Self {
39 inner,
40 decryptor,
41 buffer: vec![0u8; size],
42 pos: 0,
43 cap: 0,
44 overflow: Vec::new(),
45 }
46 }
47
48 fn produce(mut self: Pin<&mut Self>) -> std::io::Result<Option<Vec<u8>>> {
52 if self.cap <= self.pos {
53 return Ok(None);
54 }
55
56 if self.cap - self.pos < 4 {
57 self.adjust_buffer(4);
59 return Ok(None);
60 }
61
62 let mut length_bytes = [0u8; 4];
71 length_bytes.copy_from_slice(&self.buffer[self.pos..self.pos + 4]);
72 let length = u32::from_le_bytes(length_bytes) as usize;
73
74 let me = self.as_mut().project();
75 if *me.cap >= *me.pos + length + 4 {
76 let decrypted = me
77 .decryptor
78 .decrypt_next(&me.buffer[*me.pos + 4..*me.pos + 4 + length])
79 .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
80
81 *me.pos += 4 + length;
82 if *me.pos == *me.cap {
83 *me.pos = 0;
84 *me.cap = 0;
85 }
86
87 Ok(Some(decrypted))
88 } else {
89 self.adjust_buffer(length + 4);
90 Ok(None)
91 }
92 }
93
94 fn adjust_buffer(self: Pin<&mut Self>, desired_additional: usize) {
104 let me = self.project();
105 if *me.cap + desired_additional >= me.buffer.len() && *me.pos > 0 {
106 me.buffer.copy_within(*me.pos..*me.cap, 0);
107 *me.cap -= *me.pos;
108 *me.pos = 0;
109 }
110
111 if *me.pos + desired_additional > me.buffer.len() {
112 me.buffer.resize(me.buffer.len() * 2, 0);
113 }
114 }
115
116 pub fn buffer(&self) -> &[u8] {
122 &self.buffer[self.pos..]
123 }
124}
125
126impl<T, A, S> AsyncRead for ReadHalf<T, Decryptor<A, S>>
127where
128 T: AsyncRead,
129 S: StreamPrimitive<A>,
130 A: AeadInOut,
131 A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
132 NonceSize<A, S>: ArraySize,
133{
134 fn poll_read(
143 mut self: Pin<&mut Self>,
144 cx: &mut std::task::Context<'_>,
145 buf: &mut tokio::io::ReadBuf<'_>,
146 ) -> std::task::Poll<std::io::Result<()>> {
147 loop {
148 if !self.overflow.is_empty() {
149 let me = self.as_mut().project();
150 let n = std::cmp::min(me.overflow.len(), buf.remaining());
151 buf.put_slice(&me.overflow[..n]);
152 me.overflow.drain(..n);
153 return std::task::Poll::Ready(Ok(()));
154 }
155
156 if let Some(decrypted) = self.as_mut().produce()? {
157 let n = std::cmp::min(decrypted.len(), buf.remaining());
158 buf.put_slice(&decrypted[..n]);
159 if n < decrypted.len() {
160 let me = self.as_mut().project();
161 me.overflow.extend_from_slice(&decrypted[n..]);
162 }
163 return std::task::Poll::Ready(Ok(()));
164 }
165
166 if ready!(self.as_mut().poll_fill_buf(cx))?.is_empty() {
167 return std::task::Poll::Ready(Ok(()));
168 }
169 }
170 }
171}
172
173impl<R: AsyncRead, A, S> tokio::io::AsyncBufRead for ReadHalf<R, Decryptor<A, S>>
174where
175 S: StreamPrimitive<A>,
176 A: AeadInOut,
177 A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
178 NonceSize<A, S>: ArraySize,
179{
180 fn poll_fill_buf(
181 self: Pin<&mut Self>,
182 cx: &mut std::task::Context<'_>,
183 ) -> std::task::Poll<std::io::Result<&[u8]>> {
184 let me = self.project();
185
186 let mut buf = tokio::io::ReadBuf::new(&mut me.buffer[*me.cap..]);
187 ready!(me.inner.poll_read(cx, &mut buf))?;
188 if !buf.filled().is_empty() {
189 *me.cap += buf.filled().len();
190 }
191
192 std::task::Poll::Ready(Ok(&me.buffer[*me.pos..*me.cap]))
193 }
194
195 fn consume(self: Pin<&mut Self>, amt: usize) {
196 let me = self.project();
197 *me.pos += amt;
198 if *me.pos >= *me.cap {
199 *me.pos = 0;
200 *me.cap = 0;
201 }
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use std::{assert_eq, time::Duration};
208
209 use aead_stream::{DecryptorLE31, EncryptorLE31};
210 use chacha20poly1305::{KeyInit, XChaCha20Poly1305};
211 use tokio::io::{AsyncReadExt, AsyncWriteExt};
212
213 use crate::get_key;
214
215 use super::*;
216
217 #[tokio::test]
218 pub async fn test_crypto_stream_read_half() {
219 let key: [u8; 32] = get_key("key", "group");
220 let start_nonce = [0u8; 20];
221
222 let (rx, mut tx) = tokio::io::duplex(100);
223
224 tokio::spawn(async move {
225 let encrypted_content = {
226 let mut encryptor: EncryptorLE31<XChaCha20Poly1305> =
227 EncryptorLE31::from_aead(
228 XChaCha20Poly1305::new((&key).into()),
229 (&start_nonce).into(),
230 );
231
232 let mut expected = Vec::new();
233
234 for data in ["some content", "some other content", "even more content"] {
235 let mut encrypted = encryptor.encrypt_next(data.as_bytes()).unwrap();
236 expected.extend((encrypted.len() as u32).to_le_bytes());
237 expected.append(&mut encrypted);
238 }
239
240 expected
241 };
242
243 for chunk in encrypted_content.chunks(10) {
244 let _ = tx.write(chunk).await;
245 tokio::time::sleep(Duration::from_millis(20)).await;
246 }
247 });
248
249 tokio::time::sleep(Duration::from_millis(20)).await;
250
251 let decryptor = DecryptorLE31::from_aead(
252 XChaCha20Poly1305::new((&key).into()),
253 (&start_nonce).into(),
254 );
255 let mut reader = ReadHalf::new(rx, decryptor);
256
257 let mut plain_content = String::new();
258 let _ = reader.read_to_string(&mut plain_content).await;
259
260 assert_eq!(
261 plain_content,
262 "some contentsome other contenteven more content"
263 );
264 }
265
266 #[tokio::test]
267 pub async fn test_read_invalid_data() {
268 let key: [u8; 32] = get_key("key", "group");
269 let start_nonce = [0u8; 20];
270
271 let (rx, _tx) = tokio::io::duplex(100);
272
273 let decryptor = DecryptorLE31::from_aead(
274 XChaCha20Poly1305::new((&key).into()),
275 (&start_nonce).into(),
276 );
277 let mut reader = ReadHalf::new(rx, decryptor);
278 let mut reader_data = Vec::from_iter(10u32.to_le_bytes());
279 reader_data.extend_from_slice(&[0u8; 20]);
280
281 reader.cap = reader_data.len();
282 reader.buffer = reader_data;
283
284 let mut buf = [0u8; 1024];
285
286 assert!(reader.read(&mut buf).await.is_err());
287 assert!(reader.read(&mut buf).await.is_err());
288 }
289
290 #[tokio::test]
291 pub async fn test_read_with_header_split_near_buffer_end() {
292 let key: [u8; 32] = get_key("key", "group");
293 let start_nonce = [0u8; 20];
294
295 let mut encryptor: EncryptorLE31<XChaCha20Poly1305> =
296 EncryptorLE31::from_aead(
297 XChaCha20Poly1305::new((&key).into()),
298 (&start_nonce).into(),
299 );
300
301 let mut record1 = {
302 let mut encrypted = encryptor.encrypt_next("hi".as_bytes()).unwrap();
303 let mut record = Vec::new();
304 record.extend((encrypted.len() as u32).to_le_bytes());
305 record.append(&mut encrypted);
306 record
307 };
308
309 let record2 = {
310 let mut encrypted = encryptor.encrypt_next("there".as_bytes()).unwrap();
311 let mut record = Vec::new();
312 record.extend((encrypted.len() as u32).to_le_bytes());
313 record.append(&mut encrypted);
314 record
315 };
316
317 let (record2_head, record2_tail) = record2.split_at(2);
320
321 let (rx, mut tx) = tokio::io::duplex(4096);
322 tx.write_all(record2_tail).await.unwrap();
323
324 let decryptor = DecryptorLE31::from_aead(
325 XChaCha20Poly1305::new((&key).into()),
326 (&start_nonce).into(),
327 );
328 let mut reader = ReadHalf::with_capacity(rx, decryptor, record1.len() + record2_head.len());
329
330 record1.extend_from_slice(record2_head);
335 reader.buffer = record1.clone();
336 reader.cap = record1.len();
337 reader.pos = 0;
338
339 let mut buf = [0u8; 1024];
340 let n = reader.read(&mut buf).await.unwrap();
341 assert_eq!(&buf[..n], b"hi");
342
343 let n = reader.read(&mut buf).await.unwrap();
344 assert_eq!(&buf[..n], b"there");
345 }
346
347 #[tokio::test]
348 pub async fn test_read_buffer_smaller_than_message() {
349 let key: [u8; 32] = get_key("key", "group");
350 let start_nonce = [0u8; 20];
351
352 let (rx, mut tx) = tokio::io::duplex(4096);
353
354 tokio::spawn(async move {
355 let mut encryptor: EncryptorLE31<XChaCha20Poly1305> =
356 EncryptorLE31::from_aead(
357 XChaCha20Poly1305::new((&key).into()),
358 (&start_nonce).into(),
359 );
360
361 let content = "a".repeat(500);
362 let mut encrypted = encryptor.encrypt_next(content.as_bytes()).unwrap();
363 let mut encrypted_content = Vec::new();
364 encrypted_content.extend((encrypted.len() as u32).to_le_bytes());
365 encrypted_content.append(&mut encrypted);
366
367 let _ = tx.write_all(&encrypted_content).await;
368 });
369
370 let decryptor = DecryptorLE31::from_aead(
371 XChaCha20Poly1305::new((&key).into()),
372 (&start_nonce).into(),
373 );
374 let mut reader = ReadHalf::new(rx, decryptor);
375
376 let mut plain_content = String::new();
379 let mut small_buf = [0u8; 64];
380 loop {
381 let n = reader.read(&mut small_buf).await.unwrap();
382 if n == 0 {
383 break;
384 }
385 plain_content.push_str(std::str::from_utf8(&small_buf[..n]).unwrap());
386 }
387
388 assert_eq!(plain_content, "a".repeat(500));
389 }
390}