wolf_crypto/aead/chacha20_poly1305/
io.rs

1use crate::aead::chacha20_poly1305::{ChaCha20Poly1305, states::UpdatingAad};
2use crate::aead::Aad as _;
3use crate::aead::chacha20_poly1305::states::Updating;
4use crate::{can_cast_u32, Unspecified};
5
6/// Combines a `ChaCha20Poly1305` instance in its AAD updating state with an IO type,
7/// allowing for streaming AAD processing through standard Read and Write traits.
8///
9/// # Example
10///
11/// ```
12/// # use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
13/// # use wolf_crypto::MakeOpaque;
14#[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "# use embedded_io::Write;")]
15#[cfg_attr(feature = "std", doc = "# use std::io::Write;")]
16#[cfg_attr(
17    all(feature = "embedded-io", not(feature = "std")),
18    doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
19)]
20#[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
21/// # let key = Key::new([0u8; 32]);
22/// # let iv = [0u8; 12];
23/// # let mut aad_buffer = [0u8; 64];
24/// #
25/// let mut aad_io = ChaCha20Poly1305::new_encrypt(key, iv)
26///     .aad_io(&mut aad_buffer[..]);
27///
28/// aad_io.write(b"Additional Authenticated Data")?;
29/// let (aead, _) = aad_io.finish();
30///
31/// // Continue with encryption...
32/// # Ok(())
33/// # }
34/// ```
35#[must_use]
36pub struct Aad<S: UpdatingAad, IO> {
37    aad: ChaCha20Poly1305<S>,
38    io: IO
39}
40
41impl<S: UpdatingAad, IO> Aad<S, IO> {
42    /// Creates a new `Aad` instance.
43    ///
44    /// # Arguments
45    ///
46    /// * `aad`: A ChaCha20Poly1305 instance in its AAD updating state.
47    /// * `io`: The underlying IO type for reading or writing AAD.
48    pub const fn new(aad: ChaCha20Poly1305<S>, io: IO) -> Self {
49        Self { aad, io }
50    }
51
52    /// Signals that no more Additional Authenticated Data (AAD) will be provided, transitioning the
53    /// cipher to the data processing state.
54    ///
55    /// This method finalizes the AAD input phase. After calling `finish`, you may [`finalize`] the
56    /// state machine, or begin updating the cipher with data to be encrypted / decrypted.
57    ///
58    /// # Example
59    ///
60    /// ```
61    /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
62    /// use wolf_crypto::MakeOpaque;
63    ///
64    #[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "use embedded_io::Write;")]
65    #[cfg_attr(feature = "std", doc = "use std::io::Write;")]
66    #[cfg_attr(
67        all(feature = "embedded-io", not(feature = "std")),
68        doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
69    )]
70    #[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
71    /// let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
72    /// let mut some_io_write_implementor = [7u8; 64];
73    ///
74    /// let mut io = ChaCha20Poly1305::new_encrypt(key, iv)
75    ///     .aad_io(some_io_write_implementor.as_mut_slice());
76    ///
77    /// let read = io.write(b"hello world")?;
78    /// // _my_writer in this case is the remaining unwritten bytes...
79    /// let (aead, _my_writer) = io.finish();
80    ///
81    /// assert_eq!(&some_io_write_implementor[..read], b"hello world");
82    ///
83    /// let tag = aead.finalize();
84    /// # assert_ne!(tag, wolf_crypto::aead::Tag::new_zeroed()); // no warnings
85    /// # Ok(()) }
86    /// ```
87    ///
88    /// [`finalize`]: ChaCha20Poly1305::finalize
89    #[inline]
90    pub fn finish(self) -> (ChaCha20Poly1305<S::Mode>, IO) {
91        (self.aad.finish(), self.io)
92    }
93}
94
95std! {
96    use std::io as std_io;
97
98    impl<S, IO> std_io::Write for Aad<S, IO>
99        where
100            S: UpdatingAad,
101            IO: std_io::Write
102    {
103        #[inline]
104        fn write(&mut self, buf: &[u8]) -> std_io::Result<usize> {
105            if !buf.is_valid_size() { return Err(std_io::Error::other(Unspecified)) }
106            self.io.write(buf).map(
107                // SAFETY: We ensured the AAD meets the required preconditions with checking
108                // is_valid_size.
109                |amount| unsafe { self.aad.update_aad_unchecked(&buf[..amount]); amount }
110            )
111        }
112
113        #[inline]
114        fn write_all(&mut self, buf: &[u8]) -> std_io::Result<()> {
115            if !buf.is_valid_size() { return Err(std_io::Error::other(Unspecified)) }
116            // SAFETY: We ensured the AAD meets the required preconditions with checking
117            // is_valid_size.
118            self.io.write_all(buf).map(|()| unsafe { self.aad.update_aad_unchecked(buf) })
119        }
120
121        #[inline]
122        fn flush(&mut self) -> std_io::Result<()> {
123            self.io.flush()
124        }
125    }
126
127    impl<S, IO> std_io::Read for Aad<S, IO>
128        where
129            S: UpdatingAad,
130            IO: std_io::Read
131    {
132        #[inline]
133        fn read(&mut self, buf: &mut [u8]) -> std_io::Result<usize> {
134            // we must ensure we are infallible prior to writing to the buffer
135            if !buf.is_valid_size() { return Err(std_io::Error::other(Unspecified)) }
136            match self.io.read(buf) {
137                Ok(read) => {
138                    // SAFETY: We ensured the AAD meets the required preconditions with checking
139                    // is_valid_size.
140                    unsafe { self.aad.update_aad_unchecked(&buf[..read]); }
141                    Ok(read)
142                },
143                res @ Err(_) => res
144            }
145        }
146
147        #[inline]
148        fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std_io::Result<usize> {
149            // we must ensure we are infallible prior to writing to the buffer
150            if !buf.is_valid_size() { return Err(std_io::Error::other(Unspecified)) }
151
152            let init_len = buf.len();
153            match self.io.read_to_end(buf) {
154                Ok(read) => {
155                    unsafe {
156                        // SAFETY: We ensured the AAD meets the required preconditions with checking
157                        // is_valid_size.
158                        self.aad.update_aad_unchecked(&buf.as_mut_slice()[init_len..init_len + read])
159                    };
160                    Ok(read)
161                },
162                res @ Err(_) => res
163            }
164        }
165    }
166}
167
168no_std_io! {
169    use embedded_io::{self as eio, ErrorType};
170
171    impl<S: UpdatingAad, IO> ErrorType for Aad<S, IO> {
172        type Error = Unspecified;
173    }
174
175    impl<S, IO> eio::Write for Aad<S, IO>
176        where
177            S: UpdatingAad,
178            IO: eio::Write
179    {
180        #[inline]
181        fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
182            if !buf.is_valid_size() { return Err(Unspecified) }
183            match self.io.write(buf) {
184                Ok(amount) => {
185                    // SAFETY: We ensured the AAD meets the required preconditions with checking
186                    // is_valid_size.
187                    unsafe { self.aad.update_aad_unchecked(&buf[..amount]); }
188                    Ok(amount)
189                },
190                Err(_) => Err(Unspecified)
191            }
192        }
193
194        #[inline]
195        fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
196            if !buf.is_valid_size() { return Err(Unspecified) }
197            match self.io.write_all(buf) {
198                Ok(()) => {
199                    // SAFETY: We ensured the AAD meets the required preconditions with checking
200                    // is_valid_size.
201                    unsafe { self.aad.update_aad_unchecked(buf); }
202                    Ok(())
203                },
204                Err(_) => Err(Unspecified)
205            }
206        }
207
208        #[inline]
209        fn flush(&mut self) -> Result<(), Self::Error> {
210            self.io.flush().map_err(|_| Unspecified)
211        }
212    }
213
214    impl<S, IO> eio::Read for Aad<S, IO>
215        where
216            S: UpdatingAad,
217            IO: eio::Read
218    {
219        #[inline]
220        fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
221            // we must ensure we are infallible prior to writing to the buffer
222            if !buf.is_valid_size() { return Err(Unspecified) }
223            match self.io.read(buf) {
224                Ok(read) => {
225                    // SAFETY: We ensured the AAD meets the required preconditions with checking
226                    // is_valid_size.
227                    unsafe { self.aad.update_aad_unchecked(&buf[..read]); }
228                    Ok(read)
229                },
230                Err(_) => Err(Unspecified)
231            }
232        }
233    }
234}
235
236/// Combines a `ChaCha20Poly1305` instance in its data updating state with an IO type,
237/// allowing for streaming encryption or decryption through the standard Read trait.
238///
239/// # Example
240///
241/// ```
242/// # use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
243/// # use wolf_crypto::MakeOpaque;
244#[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "# use embedded_io::Read;")]
245#[cfg_attr(feature = "std", doc = "# use std::io::Read;")]
246#[cfg_attr(
247    all(feature = "embedded-io", not(feature = "std")),
248    doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
249)]
250#[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
251/// # let key = Key::new([0u8; 32]);
252/// # let iv = [0u8; 12];
253/// # let plaintext = b"Secret message";
254/// # let mut ciphertext = [0u8; 64];
255/// #
256/// let mut io = ChaCha20Poly1305::new_encrypt(key, iv)
257///     .data_io(plaintext.as_slice());
258///
259/// let bytes_read = io.read(&mut ciphertext)?;
260/// let (aead, _) = io.finish();
261///
262/// assert_ne!(plaintext.as_slice(), &ciphertext[..bytes_read]);
263/// assert_eq!(bytes_read, plaintext.len());
264///
265/// let tag = aead.finalize();
266/// # Ok(())
267/// # }
268/// ```
269#[must_use]
270pub struct Data<S: Updating, IO> {
271    aead: ChaCha20Poly1305<S>,
272    io: IO
273}
274
275impl<S: Updating, IO> Data<S, IO> {
276    /// Creates a new `Data` instance.
277    ///
278    /// # Arguments
279    ///
280    /// * `aead`: A ChaCha20Poly1305 instance in its data updating state.
281    /// * `io`: The underlying IO type for reading data to be encrypted or decrypted.
282    pub const fn new(aead: ChaCha20Poly1305<S>, io: IO) -> Self {
283        Self { aead, io }
284    }
285
286    /// Finalizes the data processing and returns the updated `ChaCha20Poly1305` instance.
287    ///
288    /// # Returns
289    ///
290    /// A tuple containing:
291    /// - The updated ChaCha20Poly1305 instance, ready for finalization.
292    /// - The underlying IO type.
293    ///
294    /// # Example
295    ///
296    /// ```
297    /// # use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
298    /// # use wolf_crypto::MakeOpaque;
299    #[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "# use embedded_io::Read;")]
300    #[cfg_attr(feature = "std", doc = "# use std::io::Read;")]
301    #[cfg_attr(
302        all(feature = "embedded-io", not(feature = "std")),
303        doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
304    )]
305    #[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
306    /// # let key = Key::new([0u8; 32]);
307    /// # let iv = [0u8; 12];
308    /// # let plaintext = b"Secret message";
309    /// # let mut ciphertext = [0u8; 64];
310    /// let mut data_io = ChaCha20Poly1305::new_encrypt(key, iv)
311    ///     .data_io(plaintext.as_slice());
312    ///
313    /// data_io.read(&mut ciphertext)?;
314    /// let (aead, _) = data_io.finish();
315    ///
316    /// let tag = aead.finalize();
317    /// # Ok(())
318    /// # }
319    /// ```
320    #[inline]
321    pub fn finish(self) -> (ChaCha20Poly1305<S>, IO) {
322        (self.aead, self.io)
323    }
324}
325
326std! {
327    impl<S, IO> std_io::Read for Data<S, IO>
328        where
329            S: Updating,
330            IO: std_io::Read
331    {
332        #[inline]
333        fn read(&mut self, buf: &mut [u8]) -> std_io::Result<usize> {
334            // We will do our safety checks in advance, we read from the io type we're wrapping,
335            // and then we fail encrypt, potentially leaking sensitive data. So, doing these
336            // checks in advance is necessary.
337            if !can_cast_u32(buf.len()) { return Err(std_io::Error::other(Unspecified)) }
338
339            self.io.read(buf).map(|amount| unsafe {
340                self.aead.update_in_place_unchecked(&mut buf[..amount]);
341                amount
342            })
343        }
344    }
345}
346
347no_std_io! {
348    impl<S: Updating, IO: ErrorType> ErrorType for Data<S, IO> {
349        type Error = Unspecified;
350    }
351
352    impl<S, IO> eio::Read for Data<S, IO>
353        where
354            S: Updating,
355            IO: eio::Read
356    {
357        #[inline]
358        fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
359            if !can_cast_u32(buf.len()) { return Err(Unspecified) }
360
361            match self.io.read(buf) {
362                Ok(amount) => {
363                    unsafe { self.aead.update_in_place_unchecked(&mut buf[..amount]) };
364                    Ok(amount)
365                },
366                Err(_) => Err(Unspecified)
367            }
368        }
369    }
370}