chacha20poly1305/
cipher.rs1use ::cipher::{StreamCipher, StreamCipherSeek};
4use aead::Error;
5use aead::{array::Array, inout::InOutBuf};
6use poly1305::{
7 Poly1305,
8 universal_hash::{KeyInit, UniversalHash},
9};
10
11use super::Tag;
12
13const BLOCK_SIZE: usize = 64;
15
16const MAX_BLOCKS: usize = u32::MAX as usize;
19
20pub(crate) struct Cipher<C>
22where
23 C: StreamCipher + StreamCipherSeek,
24{
25 cipher: C,
26 mac: Poly1305,
27}
28
29impl<C> Cipher<C>
30where
31 C: StreamCipher + StreamCipherSeek,
32{
33 pub(crate) fn new(mut cipher: C) -> Self {
35 let mut mac_key = poly1305::Key::default();
37 cipher.apply_keystream(&mut mac_key);
38
39 let mac = Poly1305::new(&mac_key);
40 #[cfg(feature = "zeroize")]
41 {
42 use zeroize::Zeroize;
43 mac_key.zeroize();
44 }
45
46 cipher.seek(BLOCK_SIZE as u64);
48
49 Self { cipher, mac }
50 }
51
52 pub(crate) fn encrypt_inout_detached(
54 mut self,
55 associated_data: &[u8],
56 mut buffer: InOutBuf<'_, '_, u8>,
57 ) -> Result<Tag, Error> {
58 if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS {
59 return Err(Error);
60 }
61
62 self.mac.update_padded(associated_data);
63
64 self.cipher.apply_keystream_inout(buffer.reborrow());
67 self.mac.update_padded(buffer.get_out());
68
69 self.authenticate_lengths(associated_data, buffer.get_out())?;
70 Ok(self.mac.finalize())
71 }
72
73 pub(crate) fn decrypt_inout_detached(
76 mut self,
77 associated_data: &[u8],
78 buffer: InOutBuf<'_, '_, u8>,
79 tag: &Tag,
80 ) -> Result<(), Error> {
81 if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS {
82 return Err(Error);
83 }
84
85 self.mac.update_padded(associated_data);
86 self.mac.update_padded(buffer.get_in());
87 self.authenticate_lengths(associated_data, buffer.get_in())?;
88
89 if self.mac.verify(tag).is_ok() {
91 self.cipher.apply_keystream_inout(buffer);
94 Ok(())
95 } else {
96 Err(Error)
97 }
98 }
99
100 fn authenticate_lengths(&mut self, associated_data: &[u8], buffer: &[u8]) -> Result<(), Error> {
102 let associated_data_len: u64 = associated_data.len().try_into().map_err(|_| Error)?;
103 let buffer_len: u64 = buffer.len().try_into().map_err(|_| Error)?;
104
105 let mut block = Array::default();
106 block[..8].copy_from_slice(&associated_data_len.to_le_bytes());
107 block[8..].copy_from_slice(&buffer_len.to_le_bytes());
108 self.mac.update(&[block]);
109
110 Ok(())
111 }
112}