1use crate::Tag;
7use aead::{
8 generic_array::{
9 typenum::{Unsigned, U16},
10 ArrayLength, GenericArray,
11 },
12 Buffer, Error,
13};
14use aes::{Aes128, Aes256};
15use cipher::{
16 BlockCipher, BlockEncryptMut, InnerIvInit, Key, KeyInit, KeySizeUser, StreamCipherCore,
17};
18use cmac::Cmac;
19use core::ops::Add;
20use dbl::Dbl;
21use digest::{CtOutput, FixedOutputReset, Mac};
22use zeroize::Zeroize;
23
24#[cfg(feature = "alloc")]
25use alloc::vec::Vec;
26
27#[cfg(feature = "pmac")]
28use pmac::Pmac;
29
30pub const IV_SIZE: usize = 16;
32
33pub const MAX_HEADERS: usize = 126;
35
36type Ctr128BE<C> = ctr::CtrCore<C, ctr::flavors::Ctr128BE>;
38
39pub type KeySize<C> = <<C as KeySizeUser>::KeySize as Add>::Output;
41
42pub struct Siv<C, M>
45where
46 C: BlockCipher<BlockSize = U16> + BlockEncryptMut + KeyInit + KeySizeUser,
47 M: Mac<OutputSize = U16>,
48{
49 encryption_key: Key<C>,
50 mac: M,
51}
52
53pub type CmacSiv<BlockCipher> = Siv<BlockCipher, Cmac<BlockCipher>>;
55
56#[cfg(feature = "pmac")]
58#[cfg_attr(docsrs, doc(cfg(feature = "pmac")))]
59pub type PmacSiv<BlockCipher> = Siv<BlockCipher, Pmac<BlockCipher>>;
60
61pub type Aes128Siv = CmacSiv<Aes128>;
63
64pub type Aes256Siv = CmacSiv<Aes256>;
66
67#[cfg(feature = "pmac")]
69#[cfg_attr(docsrs, doc(cfg(feature = "pmac")))]
70pub type Aes128PmacSiv = PmacSiv<Aes128>;
71
72#[cfg(feature = "pmac")]
74#[cfg_attr(docsrs, doc(cfg(feature = "pmac")))]
75pub type Aes256PmacSiv = PmacSiv<Aes256>;
76
77impl<C, M> KeySizeUser for Siv<C, M>
78where
79 C: BlockCipher<BlockSize = U16> + BlockEncryptMut + KeyInit + KeySizeUser,
80 M: Mac<OutputSize = U16> + FixedOutputReset + KeyInit,
81 <C as KeySizeUser>::KeySize: Add,
82 KeySize<C>: ArrayLength<u8>,
83{
84 type KeySize = KeySize<C>;
85}
86
87impl<C, M> KeyInit for Siv<C, M>
88where
89 C: BlockCipher<BlockSize = U16> + BlockEncryptMut + KeyInit + KeySizeUser,
90 M: Mac<OutputSize = U16> + FixedOutputReset + KeyInit,
91 <C as KeySizeUser>::KeySize: Add,
92 KeySize<C>: ArrayLength<u8>,
93{
94 fn new(key: &GenericArray<u8, KeySize<C>>) -> Self {
96 let encryption_key = GenericArray::clone_from_slice(&key[M::key_size()..]);
98
99 let mac = <M as Mac>::new(GenericArray::from_slice(&key[..M::KeySize::to_usize()]));
101
102 Self {
103 encryption_key,
104 mac,
105 }
106 }
107}
108
109impl<C, M> Siv<C, M>
110where
111 C: BlockCipher<BlockSize = U16> + BlockEncryptMut + KeyInit + KeySizeUser,
112 M: Mac<OutputSize = U16> + FixedOutputReset + KeyInit,
113{
114 #[cfg(feature = "alloc")]
122 pub fn encrypt<I, T>(&mut self, headers: I, plaintext: &[u8]) -> Result<Vec<u8>, Error>
123 where
124 I: IntoIterator<Item = T>,
125 T: AsRef<[u8]>,
126 {
127 let mut buffer = Vec::with_capacity(plaintext.len() + IV_SIZE);
128 buffer.extend_from_slice(plaintext);
129 self.encrypt_in_place(headers, &mut buffer)?;
130 Ok(buffer)
131 }
132
133 pub fn encrypt_in_place<I, T>(
140 &mut self,
141 headers: I,
142 buffer: &mut dyn Buffer,
143 ) -> Result<(), Error>
144 where
145 I: IntoIterator<Item = T>,
146 T: AsRef<[u8]>,
147 {
148 let pt_len = buffer.len();
149
150 buffer.extend_from_slice(Tag::default().as_slice())?;
152
153 buffer.as_mut().copy_within(..pt_len, IV_SIZE);
155
156 let tag = self.encrypt_in_place_detached(headers, &mut buffer.as_mut()[IV_SIZE..])?;
157 buffer.as_mut()[..IV_SIZE].copy_from_slice(tag.as_slice());
158 Ok(())
159 }
160
161 pub fn encrypt_in_place_detached<I, T>(
168 &mut self,
169 headers: I,
170 plaintext: &mut [u8],
171 ) -> Result<Tag, Error>
172 where
173 I: IntoIterator<Item = T>,
174 T: AsRef<[u8]>,
175 {
176 let siv_tag = s2v(&mut self.mac, headers, plaintext)?;
178 self.xor_with_keystream(siv_tag, plaintext);
179 Ok(siv_tag)
180 }
181
182 #[cfg(feature = "alloc")]
184 pub fn decrypt<I, T>(&mut self, headers: I, ciphertext: &[u8]) -> Result<Vec<u8>, Error>
185 where
186 I: IntoIterator<Item = T>,
187 T: AsRef<[u8]>,
188 {
189 let mut buffer = ciphertext.to_vec();
190 self.decrypt_in_place(headers, &mut buffer)?;
191 Ok(buffer)
192 }
193
194 pub fn decrypt_in_place<I, T>(
200 &mut self,
201 headers: I,
202 buffer: &mut dyn Buffer,
203 ) -> Result<(), Error>
204 where
205 I: IntoIterator<Item = T>,
206 T: AsRef<[u8]>,
207 {
208 if buffer.len() < IV_SIZE {
209 return Err(Error);
210 }
211
212 let siv_tag = Tag::clone_from_slice(&buffer.as_ref()[..IV_SIZE]);
213 self.decrypt_in_place_detached(headers, &mut buffer.as_mut()[IV_SIZE..], &siv_tag)?;
214
215 let pt_len = buffer.len() - IV_SIZE;
216
217 buffer.as_mut().copy_within(IV_SIZE.., 0);
219 buffer.truncate(pt_len);
220 Ok(())
221 }
222
223 pub fn decrypt_in_place_detached<I, T>(
230 &mut self,
231 headers: I,
232 ciphertext: &mut [u8],
233 siv_tag: &Tag,
234 ) -> Result<(), Error>
235 where
236 I: IntoIterator<Item = T>,
237 T: AsRef<[u8]>,
238 {
239 self.xor_with_keystream(*siv_tag, ciphertext);
240 let computed_siv_tag = s2v(&mut self.mac, headers, ciphertext)?;
241
242 if CtOutput::<M>::new(computed_siv_tag) == CtOutput::new(*siv_tag) {
244 Ok(())
245 } else {
246 self.xor_with_keystream(*siv_tag, ciphertext);
248 Err(Error)
249 }
250 }
251
252 fn xor_with_keystream(&mut self, mut iv: Tag, msg: &mut [u8]) {
254 iv[8] &= 0x7f;
258 iv[12] &= 0x7f;
259
260 Ctr128BE::<C>::inner_iv_init(C::new(&self.encryption_key), &iv)
261 .apply_keystream_partial(msg.into());
262 }
263}
264
265impl<C, M> Drop for Siv<C, M>
266where
267 C: BlockCipher<BlockSize = U16> + BlockEncryptMut + KeyInit + KeySizeUser,
268 M: Mac<OutputSize = U16>,
269{
270 fn drop(&mut self) {
271 self.encryption_key.zeroize()
272 }
273}
274
275fn s2v<M, I, T>(mac: &mut M, headers: I, message: &[u8]) -> Result<Tag, Error>
285where
286 M: Mac<OutputSize = U16> + FixedOutputReset,
287 I: IntoIterator<Item = T>,
288 T: AsRef<[u8]>,
289{
290 Mac::update(mac, &Tag::default());
291 let mut state = mac.finalize_reset().into_bytes();
292
293 for (i, header) in headers.into_iter().enumerate() {
294 if i >= MAX_HEADERS {
295 return Err(Error);
296 }
297
298 state = state.dbl();
299 Mac::update(mac, header.as_ref());
300 let code = mac.finalize_reset().into_bytes();
301 xor_in_place(&mut state, &code);
302 }
303
304 if message.len() >= IV_SIZE {
305 let n = message.len().checked_sub(IV_SIZE).unwrap();
306
307 Mac::update(mac, &message[..n]);
308 xor_in_place(&mut state, &message[n..]);
309 } else {
310 state = state.dbl();
311 xor_in_place(&mut state, message);
312 state[message.len()] ^= 0x80;
313 };
314
315 Mac::update(mac, state.as_ref());
316 Ok(mac.finalize_reset().into_bytes())
317}
318
319#[inline]
324fn xor_in_place(dst: &mut [u8], src: &[u8]) {
325 for (a, b) in dst[..src.len()].iter_mut().zip(src) {
326 *a ^= *b;
327 }
328}