chacha20poly1305/
cipher.rs1use ::cipher::{StreamCipher, StreamCipherSeek};
4use aead::generic_array::GenericArray;
5use aead::Error;
6use poly1305::{
7 universal_hash::{KeyInit, UniversalHash},
8 Poly1305,
9};
10use zeroize::Zeroize;
11
12use super::Tag;
13
14const BLOCK_SIZE: usize = 64;
16
17const MAX_BLOCKS: usize = core::u32::MAX as usize;
20
21pub(crate) struct Cipher<C>
23where
24 C: StreamCipher + StreamCipherSeek,
25{
26 cipher: C,
27 mac: Poly1305,
28}
29
30impl<C> Cipher<C>
31where
32 C: StreamCipher + StreamCipherSeek,
33{
34 pub(crate) fn new(mut cipher: C) -> Self {
36 let mut mac_key = poly1305::Key::default();
38 cipher.apply_keystream(&mut *mac_key);
39
40 let mac = Poly1305::new(GenericArray::from_slice(&*mac_key));
41 mac_key.zeroize();
42
43 cipher.seek(BLOCK_SIZE as u64);
45
46 Self { cipher, mac }
47 }
48
49 pub(crate) fn encrypt_in_place_detached(
51 mut self,
52 associated_data: &[u8],
53 buffer: &mut [u8],
54 ) -> Result<Tag, Error> {
55 if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS {
56 return Err(Error);
57 }
58
59 self.mac.update_padded(associated_data);
60
61 self.cipher.apply_keystream(buffer);
64 self.mac.update_padded(buffer);
65
66 self.authenticate_lengths(associated_data, buffer)?;
67 Ok(self.mac.finalize())
68 }
69
70 pub(crate) fn decrypt_in_place_detached(
73 mut self,
74 associated_data: &[u8],
75 buffer: &mut [u8],
76 tag: &Tag,
77 ) -> Result<(), Error> {
78 if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS {
79 return Err(Error);
80 }
81
82 self.mac.update_padded(associated_data);
83 self.mac.update_padded(buffer);
84 self.authenticate_lengths(associated_data, buffer)?;
85
86 if self.mac.verify(tag).is_ok() {
88 self.cipher.apply_keystream(buffer);
91 Ok(())
92 } else {
93 Err(Error)
94 }
95 }
96
97 fn authenticate_lengths(&mut self, associated_data: &[u8], buffer: &[u8]) -> Result<(), Error> {
99 let associated_data_len: u64 = associated_data.len().try_into().map_err(|_| Error)?;
100 let buffer_len: u64 = buffer.len().try_into().map_err(|_| Error)?;
101
102 let mut block = GenericArray::default();
103 block[..8].copy_from_slice(&associated_data_len.to_le_bytes());
104 block[8..].copy_from_slice(&buffer_len.to_le_bytes());
105 self.mac.update(&[block]);
106
107 Ok(())
108 }
109}