1#![cfg_attr(all(feature = "getrandom", feature = "std"), doc = "```")]
10#![cfg_attr(not(all(feature = "getrandom", feature = "std")), doc = "```ignore")]
11#![no_std]
41#![doc(
42 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
43 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
44)]
45#![deny(unsafe_code)]
46#![warn(missing_docs, rust_2018_idioms)]
47
48pub use aead::{self, consts, AeadCore, AeadInPlace, Error, Key, KeyInit, KeySizeUser};
49
50use aead::{
51 consts::{U0, U16},
52 generic_array::{typenum::Unsigned, ArrayLength, GenericArray},
53};
54use cipher::{
55 Block, BlockCipher, BlockEncrypt, BlockSizeUser, InnerIvInit, StreamCipher, StreamCipherSeek,
56};
57use core::marker::PhantomData;
58use ctr::{Ctr32BE, Ctr64BE, CtrCore};
59use subtle::ConstantTimeEq;
60
61mod private;
62
63pub type Nonce<NonceSize> = GenericArray<u8, NonceSize>;
65
66pub type Tag<TagSize> = GenericArray<u8, TagSize>;
68
69pub trait TagSize: private::SealedTag {}
74
75impl<T: private::SealedTag> TagSize for T {}
76
77pub trait NonceSize: private::SealedNonce {}
82
83impl<T: private::SealedNonce> NonceSize for T {}
84
85#[derive(Clone)]
98pub struct Ccm<C, M, N>
99where
100 C: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt,
101 M: ArrayLength<u8> + TagSize,
102 N: ArrayLength<u8> + NonceSize,
103{
104 cipher: C,
105 _pd: PhantomData<(M, N)>,
106}
107
108impl<C, M, N> Ccm<C, M, N>
109where
110 C: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt,
111 M: ArrayLength<u8> + TagSize,
112 N: ArrayLength<u8> + NonceSize,
113{
114 fn extend_nonce(nonce: &Nonce<N>) -> Block<C> {
115 let mut ext_nonce = Block::<C>::default();
116 ext_nonce[0] = N::get_l() - 1;
117 ext_nonce[1..][..nonce.len()].copy_from_slice(nonce);
118 ext_nonce
119 }
120
121 fn calc_mac(
122 &self,
123 nonce: &Nonce<N>,
124 adata: &[u8],
125 buffer: &[u8],
126 ) -> Result<Tag<C::BlockSize>, Error> {
127 let is_ad = !adata.is_empty();
128 let l = N::get_l();
129 let flags = 64 * (is_ad as u8) + 8 * M::get_m_tick() + (l - 1);
130
131 if buffer.len() > N::get_max_len() {
132 return Err(Error);
133 }
134
135 let mut b0 = Block::<C>::default();
136 b0[0] = flags;
137 let n = 1 + N::to_usize();
138 b0[1..n].copy_from_slice(nonce);
139
140 let cb = b0.len() - n;
141 if cb > 4 {
144 let b = (buffer.len() as u64).to_be_bytes();
145 b0[n..].copy_from_slice(&b[b.len() - cb..]);
146 } else {
147 let b = (buffer.len() as u32).to_be_bytes();
148 b0[n..].copy_from_slice(&b[b.len() - cb..]);
149 }
150
151 let mut mac = CbcMac::from_cipher(&self.cipher);
152 mac.block_update(&b0);
153
154 if !adata.is_empty() {
155 let alen = adata.len();
156 let (n, mut b) = fill_aad_header(alen);
157 if b.len() - n >= alen {
158 b[n..][..alen].copy_from_slice(adata);
159 mac.block_update(&b);
160 } else {
161 let (l, r) = adata.split_at(b.len() - n);
162 b[n..].copy_from_slice(l);
163 mac.block_update(&b);
164 mac.update(r);
165 }
166 }
167
168 mac.update(buffer);
169
170 Ok(mac.finalize())
171 }
172}
173
174impl<C, M, N> From<C> for Ccm<C, M, N>
175where
176 C: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt,
177 M: ArrayLength<u8> + TagSize,
178 N: ArrayLength<u8> + NonceSize,
179{
180 fn from(cipher: C) -> Self {
181 Self {
182 cipher,
183 _pd: PhantomData,
184 }
185 }
186}
187
188impl<C, M, N> KeySizeUser for Ccm<C, M, N>
189where
190 C: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit,
191 M: ArrayLength<u8> + TagSize,
192 N: ArrayLength<u8> + NonceSize,
193{
194 type KeySize = C::KeySize;
195}
196
197impl<C, M, N> KeyInit for Ccm<C, M, N>
198where
199 C: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit,
200 M: ArrayLength<u8> + TagSize,
201 N: ArrayLength<u8> + NonceSize,
202{
203 fn new(key: &Key<Self>) -> Self {
204 Self::from(C::new(key))
205 }
206}
207
208impl<C, M, N> AeadCore for Ccm<C, M, N>
209where
210 C: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt,
211 M: ArrayLength<u8> + TagSize,
212 N: ArrayLength<u8> + NonceSize,
213{
214 type NonceSize = N;
215 type TagSize = M;
216 type CiphertextOverhead = U0;
217}
218
219impl<C, M, N> AeadInPlace for Ccm<C, M, N>
220where
221 C: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt,
222 M: ArrayLength<u8> + TagSize,
223 N: ArrayLength<u8> + NonceSize,
224{
225 fn encrypt_in_place_detached(
226 &self,
227 nonce: &Nonce<N>,
228 adata: &[u8],
229 buffer: &mut [u8],
230 ) -> Result<Tag<Self::TagSize>, Error> {
231 let mut full_tag = self.calc_mac(nonce, adata, buffer)?;
232
233 let ext_nonce = Self::extend_nonce(nonce);
234 let cb = C::BlockSize::USIZE - N::USIZE - 1;
236
237 if cb > 4 {
238 let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
239 ctr.apply_keystream(&mut full_tag);
240 ctr.apply_keystream(buffer);
241 } else {
242 let mut ctr = Ctr32BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
243 ctr.apply_keystream(&mut full_tag);
244 ctr.apply_keystream(buffer);
245 }
246
247 Ok(Tag::clone_from_slice(&full_tag[..M::to_usize()]))
248 }
249
250 fn decrypt_in_place_detached(
251 &self,
252 nonce: &Nonce<N>,
253 adata: &[u8],
254 buffer: &mut [u8],
255 tag: &Tag<Self::TagSize>,
256 ) -> Result<(), Error> {
257 let ext_nonce = Self::extend_nonce(nonce);
258 let cb = C::BlockSize::USIZE - N::USIZE - 1;
260
261 if cb > 4 {
262 let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
263 ctr.seek(C::BlockSize::USIZE);
264 ctr.apply_keystream(buffer);
265 } else {
266 let mut ctr = Ctr32BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
267 ctr.seek(C::BlockSize::USIZE);
268 ctr.apply_keystream(buffer);
269 }
270
271 let mut full_tag = self.calc_mac(nonce, adata, buffer)?;
272
273 if cb > 4 {
274 let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
275 ctr.apply_keystream(&mut full_tag);
276 } else {
277 let mut ctr = Ctr32BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
278 ctr.apply_keystream(&mut full_tag);
279 }
280
281 if full_tag[..tag.len()].ct_eq(tag).into() {
282 Ok(())
283 } else {
284 buffer.iter_mut().for_each(|v| *v = 0);
285 Err(Error)
286 }
287 }
288}
289
290struct CbcMac<'a, C: BlockCipher + BlockEncrypt> {
291 cipher: &'a C,
292 state: Block<C>,
293}
294
295impl<'a, C> CbcMac<'a, C>
296where
297 C: BlockCipher + BlockEncrypt,
298{
299 fn from_cipher(cipher: &'a C) -> Self {
300 Self {
301 cipher,
302 state: Default::default(),
303 }
304 }
305
306 fn update(&mut self, data: &[u8]) {
307 let mut chunks = data.chunks_exact(C::BlockSize::USIZE);
308 for chunk in &mut chunks {
309 self.block_update(Block::<C>::from_slice(chunk));
310 }
311 let rem = chunks.remainder();
312 if !rem.is_empty() {
313 let mut bn = Block::<C>::default();
314 bn[..rem.len()].copy_from_slice(rem);
315 self.block_update(&bn);
316 }
317 }
318
319 fn block_update(&mut self, block: &Block<C>) {
320 self.state
321 .iter_mut()
322 .zip(block.iter())
323 .for_each(|(a, b)| *a ^= b);
324 self.cipher.encrypt_block(&mut self.state);
325 }
326
327 fn finalize(self) -> Block<C> {
328 self.state
329 }
330}
331
332fn fill_aad_header(adata_len: usize) -> (usize, GenericArray<u8, U16>) {
333 debug_assert_ne!(adata_len, 0);
334
335 let mut b = GenericArray::<u8, U16>::default();
336 let n = if adata_len < 0xFF00 {
337 b[..2].copy_from_slice(&(adata_len as u16).to_be_bytes());
338 2
339 } else if adata_len <= core::u32::MAX as usize {
340 b[0] = 0xFF;
341 b[1] = 0xFE;
342 b[2..6].copy_from_slice(&(adata_len as u32).to_be_bytes());
343 6
344 } else {
345 b[0] = 0xFF;
346 b[1] = 0xFF;
347 b[2..10].copy_from_slice(&(adata_len as u64).to_be_bytes());
348 10
349 };
350 (n, b)
351}
352
353#[cfg(test)]
354mod tests {
355 #[test]
356 fn fill_aad_header_test() {
357 use super::fill_aad_header;
358 use hex_literal::hex;
359
360 let (n, b) = fill_aad_header(0x0123);
361 assert_eq!(n, 2);
362 assert_eq!(b[..], hex!("01230000000000000000000000000000")[..]);
363
364 let (n, b) = fill_aad_header(0xFF00);
365 assert_eq!(n, 6);
366 assert_eq!(b[..], hex!("FFFE0000FF0000000000000000000000")[..]);
367
368 let (n, b) = fill_aad_header(0x01234567);
369 assert_eq!(n, 6);
370 assert_eq!(b[..], hex!("FFFE0123456700000000000000000000")[..]);
371
372 #[cfg(target_pointer_width = "64")]
373 {
374 let (n, b) = fill_aad_header(0x0123456789ABCDEF);
375 assert_eq!(n, 10);
376 assert_eq!(b[..], hex!("FFFF0123456789ABCDEF000000000000")[..]);
377 }
378 }
379}