async_encrypted_stream/
write_half.rs1use aead_stream::{Encryptor, NonceSize, StreamPrimitive};
2use bytes::{Buf, BufMut, BytesMut};
3use chacha20poly1305::aead::{array::ArraySize, AeadInOut};
4
5use std::{
6 ops::Sub,
7 pin::Pin,
8 task::{Poll, ready},
9};
10
11use tokio::io::AsyncWrite;
12
13use crate::{DEFAULT_BUFFER_SIZE, DEFAULT_CHUNK_SIZE};
14
15pin_project_lite::pin_project! {
16 pub struct WriteHalf<T, U> {
21 #[pin]
22 inner: T,
23 encryptor: U,
24 buffer: bytes::BytesMut,
25 chunk_size: usize
26 }
27}
28
29impl<T, A, S> WriteHalf<T, Encryptor<A, S>>
30where
31 T: AsyncWrite,
32 S: StreamPrimitive<A>,
33 A: AeadInOut,
34 A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
35 NonceSize<A, S>: ArraySize,
36{
37 pub fn new(inner: T, encryptor: Encryptor<A, S>) -> Self {
38 Self::with_capacity(inner, encryptor, DEFAULT_BUFFER_SIZE, DEFAULT_CHUNK_SIZE)
39 }
40
41 pub fn with_capacity(
42 inner: T,
43 encryptor: Encryptor<A, S>,
44 size: usize,
45 chunk_size: usize,
46 ) -> Self {
47 Self {
48 inner,
49 encryptor,
50 buffer: BytesMut::with_capacity(size),
51 chunk_size,
52 }
53 }
54
55 fn get_encrypted(&mut self, buf: &[u8]) -> std::io::Result<Vec<u8>> {
62 let mut encrypted = self
63 .encryptor
64 .encrypt_next(buf)
65 .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
66
67 let len = (encrypted.len() as u32).to_le_bytes();
68 let mut buf = Vec::with_capacity(encrypted.len() + std::mem::size_of::<u32>());
69 buf.extend_from_slice(&len);
70 buf.append(&mut encrypted);
71
72 Ok(buf)
73 }
74
75 fn flush_buf(
81 self: Pin<&mut Self>,
82 cx: &mut std::task::Context<'_>,
83 ) -> Poll<std::io::Result<()>> {
84 let mut me = self.project();
85 while me.buffer.has_remaining() {
86 match ready!(me.inner.as_mut().poll_write(cx, &me.buffer[..])) {
87 Ok(0) => {
88 return Poll::Ready(Err(std::io::Error::new(
89 std::io::ErrorKind::WriteZero,
90 "failed to write the buffered data",
91 )));
92 }
93 Ok(n) => me.buffer.advance(n),
94 Err(e) => return Poll::Ready(Err(e)),
95 }
96 }
97
98 Poll::Ready(Ok(()))
99 }
100}
101
102impl<T, A, S> AsyncWrite for WriteHalf<T, Encryptor<A, S>>
103where
104 T: AsyncWrite + Unpin,
105 S: StreamPrimitive<A>,
106 A: AeadInOut,
107 A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
108 NonceSize<A, S>: ArraySize,
109{
110 fn poll_write(
127 mut self: Pin<&mut Self>,
128 cx: &mut std::task::Context<'_>,
129 buf: &[u8],
130 ) -> std::task::Poll<Result<usize, std::io::Error>> {
131 if !self.buffer.is_empty() {
132 ready!(self.as_mut().flush_buf(cx))?
133 }
134
135 let mut total_written = 0;
136 for chunk in buf.chunks(self.chunk_size) {
137 let encrypted = self.get_encrypted(chunk)?;
138 total_written += chunk.len();
139
140 let me = self.as_mut().project();
141 match me.inner.poll_write(cx, &encrypted[..]) {
142 Poll::Ready(Ok(written)) => {
143 if written < encrypted.len() {
144 self.buffer.put(&encrypted[written..]);
145 return Poll::Ready(Ok(total_written));
146 }
147 }
148 Poll::Pending | Poll::Ready(Err(..)) => {
149 self.buffer.put(&encrypted[..]);
150 return Poll::Ready(Ok(total_written));
151 }
152 }
153 }
154 Poll::Ready(Ok(buf.len()))
155 }
156
157 fn poll_flush(
158 mut self: Pin<&mut Self>,
159 cx: &mut std::task::Context<'_>,
160 ) -> std::task::Poll<Result<(), std::io::Error>> {
161 ready!(self.as_mut().flush_buf(cx))?;
162 self.project().inner.poll_flush(cx)
163 }
164
165 fn poll_shutdown(
166 self: Pin<&mut Self>,
167 cx: &mut std::task::Context<'_>,
168 ) -> std::task::Poll<Result<(), std::io::Error>> {
169 self.project().inner.poll_shutdown(cx)
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use std::assert_eq;
176
177 use aead_stream::EncryptorLE31;
178 use chacha20poly1305::{KeyInit, XChaCha20Poly1305};
179 use tokio::io::AsyncWriteExt;
180
181 use crate::get_key;
182
183 use super::*;
184
185 #[tokio::test]
186 pub async fn test_crypto_stream_write_half() {
187 let key: [u8; 32] = get_key("key", "group");
188 let start_nonce = [0u8; 20];
189
190 let mut encryptor: EncryptorLE31<XChaCha20Poly1305> = EncryptorLE31::from_aead(
191 XChaCha20Poly1305::new((&key).into()),
192 (&start_nonce).into(),
193 );
194
195 let expected = {
196 let mut encrypted = encryptor.encrypt_next("some content".as_bytes()).unwrap();
197 let mut expected = Vec::new();
198 expected.extend((encrypted.len() as u32).to_le_bytes());
199 expected.append(&mut encrypted);
200
201 expected
202 };
203
204 let mut writer = WriteHalf::new(
205 tokio::io::BufWriter::new(Vec::new()),
206 EncryptorLE31::from_aead(
207 XChaCha20Poly1305::new((&key).into()),
208 (&start_nonce).into(),
209 ),
210 );
211
212 assert_eq!(
213 writer.write(b"some content").await.unwrap(),
214 "some content".len()
215 );
216
217 assert_eq!(expected, writer.inner.buffer())
218 }
219}