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}