1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8#![deny(unsafe_code)]
9#![warn(missing_docs, rust_2018_idioms)]
10
11pub mod consts {
13 pub use cipher::consts::{U0, U12, U15, U16, U6};
14}
15
16mod util;
17
18pub use aead::{
19 self, generic_array::GenericArray, AeadCore, AeadInPlace, Error, KeyInit, KeySizeUser,
20};
21
22use crate::util::{double, inplace_xor, ntz, Block};
23use cipher::{
24 consts::{U0, U12, U16},
25 BlockDecrypt, BlockEncrypt, BlockSizeUser,
26};
27use core::marker::PhantomData;
28use subtle::ConstantTimeEq;
29
30#[cfg(target_pointer_width = "64")]
36const L_TABLE_SIZE: usize = 32;
37
38#[cfg(target_pointer_width = "32")]
42const L_TABLE_SIZE: usize = 16;
43
44pub const A_MAX: usize = 1 << (L_TABLE_SIZE + 4);
46pub const P_MAX: usize = 1 << (L_TABLE_SIZE + 4);
48pub const C_MAX: usize = 1 << (L_TABLE_SIZE + 4);
50
51pub type Nonce<NonceSize> = GenericArray<u8, NonceSize>;
53
54pub type Tag<TagSize> = GenericArray<u8, TagSize>;
56
57mod sealed {
58 use aead::generic_array::{
59 typenum::{GrEq, IsGreaterOrEqual, IsLessOrEqual, LeEq, NonZero, U15, U16, U6},
60 ArrayLength,
61 };
62
63 pub trait NonceSizes: ArrayLength<u8> {}
65
66 impl<T> NonceSizes for T
67 where
68 T: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
69 GrEq<T, U6>: NonZero,
70 LeEq<T, U15>: NonZero,
71 {
72 }
73
74 pub trait TagSizes: ArrayLength<u8> {}
76
77 impl<T> TagSizes for T
78 where
79 T: ArrayLength<u8> + NonZero + IsLessOrEqual<U16>,
80 LeEq<T, U16>: NonZero,
81 {
82 }
83}
84
85#[derive(Clone)]
126pub struct Ocb3<Cipher, NonceSize = U12, TagSize = U16>
127where
128 NonceSize: sealed::NonceSizes,
129 TagSize: sealed::TagSizes,
130{
131 cipher: Cipher,
132 nonce_size: PhantomData<NonceSize>,
133 tag_size: PhantomData<TagSize>,
134 ll_star: Block,
136 ll_dollar: Block,
137 ll: [Block; L_TABLE_SIZE],
139}
140
141type SumSize = U16;
143type Sum = GenericArray<u8, SumSize>;
144
145impl<Cipher, NonceSize, TagSize> KeySizeUser for Ocb3<Cipher, NonceSize, TagSize>
146where
147 Cipher: KeySizeUser,
148 NonceSize: sealed::NonceSizes,
149 TagSize: sealed::TagSizes,
150{
151 type KeySize = Cipher::KeySize;
152}
153
154impl<Cipher, NonceSize, TagSize> KeyInit for Ocb3<Cipher, NonceSize, TagSize>
155where
156 Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit + BlockDecrypt,
157 NonceSize: sealed::NonceSizes,
158 TagSize: sealed::TagSizes,
159{
160 fn new(key: &aead::Key<Self>) -> Self {
161 Cipher::new(key).into()
162 }
163}
164
165impl<Cipher, NonceSize, TagSize> AeadCore for Ocb3<Cipher, NonceSize, TagSize>
166where
167 NonceSize: sealed::NonceSizes,
168 TagSize: sealed::TagSizes,
169{
170 type NonceSize = NonceSize;
171 type TagSize = TagSize;
172 type CiphertextOverhead = U0;
173}
174
175impl<Cipher, NonceSize, TagSize> From<Cipher> for Ocb3<Cipher, NonceSize, TagSize>
176where
177 Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + BlockDecrypt,
178 NonceSize: sealed::NonceSizes,
179 TagSize: sealed::TagSizes,
180{
181 fn from(cipher: Cipher) -> Self {
182 let (ll_star, ll_dollar, ll) = key_dependent_variables(&cipher);
183
184 Self {
185 cipher,
186 nonce_size: PhantomData,
187 tag_size: PhantomData,
188 ll_star,
189 ll_dollar,
190 ll,
191 }
192 }
193}
194
195fn key_dependent_variables<Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt>(
198 cipher: &Cipher,
199) -> (Block, Block, [Block; L_TABLE_SIZE]) {
200 let mut zeros = [0u8; 16];
201 let ll_star = Block::from_mut_slice(&mut zeros);
202 cipher.encrypt_block(ll_star);
203 let ll_dollar = double(ll_star);
204
205 let mut ll = [Block::default(); L_TABLE_SIZE];
206 let mut ll_i = ll_dollar;
207 #[allow(clippy::needless_range_loop)]
208 for i in 0..L_TABLE_SIZE {
209 ll_i = double(&ll_i);
210 ll[i] = ll_i
211 }
212 (*ll_star, ll_dollar, ll)
213}
214
215impl<Cipher, NonceSize, TagSize> AeadInPlace for Ocb3<Cipher, NonceSize, TagSize>
216where
217 Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + BlockDecrypt,
218 NonceSize: sealed::NonceSizes,
219 TagSize: sealed::TagSizes,
220{
221 fn encrypt_in_place_detached(
222 &self,
223 nonce: &Nonce<NonceSize>,
224 associated_data: &[u8],
225 buffer: &mut [u8],
226 ) -> aead::Result<aead::Tag<Self>> {
227 if (buffer.len() > P_MAX) || (associated_data.len() > A_MAX) {
228 unimplemented!()
229 }
230
231 let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_encrypt(nonce, buffer);
233
234 let mut i = (processed_bytes / 16) + 1;
235
236 for p_i in buffer[processed_bytes..].chunks_exact_mut(16) {
238 let p_i = Block::from_mut_slice(p_i);
239 inplace_xor(&mut offset_i, &self.ll[ntz(i)]);
241 inplace_xor(&mut checksum_i, p_i);
243 let c_i = p_i;
245 inplace_xor(c_i, &offset_i);
246 self.cipher.encrypt_block(c_i);
247 inplace_xor(c_i, &offset_i);
248
249 i += 1;
250 }
251
252 if (buffer.len() % 16) != 0 {
254 let processed_bytes = (i - 1) * 16;
255 let remaining_bytes = buffer.len() - processed_bytes;
256
257 inplace_xor(&mut offset_i, &self.ll_star);
259 let mut pad = Block::default();
261 inplace_xor(&mut pad, &offset_i);
262 self.cipher.encrypt_block(&mut pad);
263 let checksum_rhs = &mut [0u8; 16];
265 checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]);
266 checksum_rhs[remaining_bytes] = 0b1000_0000;
267 inplace_xor(&mut checksum_i, Block::from_slice(checksum_rhs));
268 let p_star = &mut buffer[processed_bytes..];
270 let pad = &mut pad[..p_star.len()];
271 for (aa, bb) in p_star.iter_mut().zip(pad) {
272 *aa ^= *bb;
273 }
274 }
275
276 let tag = self.compute_tag(associated_data, &mut checksum_i, &offset_i);
277
278 Ok(tag)
279 }
280
281 fn decrypt_in_place_detached(
282 &self,
283 nonce: &Nonce<NonceSize>,
284 associated_data: &[u8],
285 buffer: &mut [u8],
286 tag: &aead::Tag<Self>,
287 ) -> aead::Result<()> {
288 let expected_tag = self.decrypt_in_place_return_tag(nonce, associated_data, buffer);
289 if expected_tag.ct_eq(tag).into() {
290 Ok(())
291 } else {
292 Err(Error)
293 }
294 }
295}
296
297impl<Cipher, NonceSize, TagSize> Ocb3<Cipher, NonceSize, TagSize>
298where
299 Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + BlockDecrypt,
300 NonceSize: sealed::NonceSizes,
301 TagSize: sealed::TagSizes,
302{
303 pub(crate) fn decrypt_in_place_return_tag(
305 &self,
306 nonce: &Nonce<NonceSize>,
307 associated_data: &[u8],
308 buffer: &mut [u8],
309 ) -> aead::Tag<Self> {
310 if (buffer.len() > C_MAX) || (associated_data.len() > A_MAX) {
311 unimplemented!()
312 }
313
314 let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_decrypt(nonce, buffer);
316
317 let mut i = (processed_bytes / 16) + 1;
318
319 for c_i in buffer[processed_bytes..].chunks_exact_mut(16) {
321 let c_i = Block::from_mut_slice(c_i);
322 inplace_xor(&mut offset_i, &self.ll[ntz(i)]);
324 let p_i = c_i;
326 inplace_xor(p_i, &offset_i);
327 self.cipher.decrypt_block(p_i);
328 inplace_xor(p_i, &offset_i);
329 inplace_xor(&mut checksum_i, p_i);
331
332 i += 1;
333 }
334
335 if (buffer.len() % 16) != 0 {
337 let processed_bytes = (i - 1) * 16;
338 let remaining_bytes = buffer.len() - processed_bytes;
339
340 inplace_xor(&mut offset_i, &self.ll_star);
342 let mut pad = Block::default();
344 inplace_xor(&mut pad, &offset_i);
345 self.cipher.encrypt_block(&mut pad);
346 let c_star = &mut buffer[processed_bytes..];
348 let pad = &mut pad[..c_star.len()];
349 for (aa, bb) in c_star.iter_mut().zip(pad) {
350 *aa ^= *bb;
351 }
352 let checksum_rhs = &mut [0u8; 16];
354 checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]);
355 checksum_rhs[remaining_bytes] = 0b1000_0000;
356 inplace_xor(&mut checksum_i, Block::from_slice(checksum_rhs));
357 }
358
359 self.compute_tag(associated_data, &mut checksum_i, &offset_i)
360 }
361
362 fn wide_encrypt(&self, nonce: &Nonce<NonceSize>, buffer: &mut [u8]) -> (usize, Block, Block) {
366 const WIDTH: usize = 2;
367 let split_into_blocks = crate::util::split_into_two_blocks;
368
369 let mut i = 1;
370
371 let mut offset_i = [Block::default(); WIDTH];
372 offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
373 let mut checksum_i = Block::default();
374 for wide_blocks in buffer.chunks_exact_mut(16 * WIDTH) {
375 let p_i = split_into_blocks(wide_blocks);
376
377 for p_ij in &p_i {
379 inplace_xor(&mut checksum_i, p_ij);
380 }
381
382 offset_i[0] = offset_i[offset_i.len() - 1];
384 inplace_xor(&mut offset_i[0], &self.ll[ntz(i)]);
385 for j in 1..p_i.len() {
386 offset_i[j] = offset_i[j - 1];
387 inplace_xor(&mut offset_i[j], &self.ll[ntz(i + j)]);
388 }
389
390 for j in 0..p_i.len() {
392 inplace_xor(p_i[j], &offset_i[j]);
393 self.cipher.encrypt_block(p_i[j]);
394 inplace_xor(p_i[j], &offset_i[j])
395 }
396
397 i += WIDTH;
398 }
399
400 let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16);
401
402 (processed_bytes, offset_i[offset_i.len() - 1], checksum_i)
403 }
404
405 fn wide_decrypt(&self, nonce: &Nonce<NonceSize>, buffer: &mut [u8]) -> (usize, Block, Block) {
409 const WIDTH: usize = 2;
410 let split_into_blocks = crate::util::split_into_two_blocks;
411
412 let mut i = 1;
413
414 let mut offset_i = [Block::default(); WIDTH];
415 offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
416 let mut checksum_i = Block::default();
417 for wide_blocks in buffer.chunks_exact_mut(16 * WIDTH) {
418 let c_i = split_into_blocks(wide_blocks);
419
420 offset_i[0] = offset_i[offset_i.len() - 1];
422 inplace_xor(&mut offset_i[0], &self.ll[ntz(i)]);
423 for j in 1..c_i.len() {
424 offset_i[j] = offset_i[j - 1];
425 inplace_xor(&mut offset_i[j], &self.ll[ntz(i + j)]);
426 }
427
428 for j in 0..c_i.len() {
431 inplace_xor(c_i[j], &offset_i[j]);
432 self.cipher.decrypt_block(c_i[j]);
433 inplace_xor(c_i[j], &offset_i[j]);
434 inplace_xor(&mut checksum_i, c_i[j]);
435 }
436
437 i += WIDTH;
438 }
439
440 let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16);
441
442 (processed_bytes, offset_i[offset_i.len() - 1], checksum_i)
443 }
444}
445
446fn nonce_dependent_variables<
449 Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt,
450 NonceSize: sealed::NonceSizes,
451>(
452 cipher: &Cipher,
453 nn: &Nonce<NonceSize>,
454 tag_len: u32,
455) -> (usize, [u8; 24]) {
456 let mut nonce = [0u8; 16];
458 nonce[0] = (((tag_len * 8) % 128) << 1) as u8;
459
460 let start = 16 - NonceSize::to_usize();
461 nonce[start..16].copy_from_slice(nn.as_slice());
462 nonce[16 - NonceSize::to_usize() - 1] |= 1;
463
464 let bottom = nonce[15] & 0b111111;
466
467 let nonce = u128::from_be_bytes(nonce);
468 let top = nonce & !0b111111;
469
470 let mut ktop = Block::from(top.to_be_bytes());
471 cipher.encrypt_block(&mut ktop);
472 let ktop = ktop.as_mut_slice();
473
474 let mut stretch = [0u8; 24];
476 stretch[..16].copy_from_slice(ktop);
477 for i in 0..8 {
478 ktop[i] ^= ktop[i + 1];
479 }
480 stretch[16..].copy_from_slice(&ktop[..8]);
481
482 (bottom as usize, stretch)
483}
484
485fn initial_offset<
488 Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt,
489 NonceSize: sealed::NonceSizes,
490>(
491 cipher: &Cipher,
492 nn: &Nonce<NonceSize>,
493 tag_size: u32,
494) -> Block {
495 let (bottom, stretch) = nonce_dependent_variables(cipher, nn, tag_size);
496 let stretch_low = u128::from_be_bytes((&stretch[..16]).try_into().unwrap());
497 let stretch_hi = u64::from_be_bytes((&stretch[16..24]).try_into().unwrap());
498 let stretch_hi = u128::from(stretch_hi);
499
500 let offset = (stretch_low << bottom) | (stretch_hi >> (64 - bottom));
502 offset.to_be_bytes().into()
503}
504
505impl<Cipher, NonceSize, TagSize> Ocb3<Cipher, NonceSize, TagSize>
506where
507 Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt,
508 NonceSize: sealed::NonceSizes,
509 TagSize: sealed::TagSizes,
510{
511 fn hash(&self, associated_data: &[u8]) -> Sum {
513 let mut offset_i = Block::default();
514 let mut sum_i = Block::default();
515
516 let mut i = 1;
517 for a_i in associated_data.chunks_exact(16) {
518 inplace_xor(&mut offset_i, &self.ll[ntz(i)]);
520 let mut a_i = *Block::from_slice(a_i);
522 inplace_xor(&mut a_i, &offset_i);
523 self.cipher.encrypt_block(&mut a_i);
524 inplace_xor(&mut sum_i, &a_i);
525
526 i += 1;
527 }
528
529 if (associated_data.len() % 16) != 0 {
531 let processed_bytes = (i - 1) * 16;
532 let remaining_bytes = associated_data.len() - processed_bytes;
533
534 inplace_xor(&mut offset_i, &self.ll_star);
536 let cipher_input = &mut [0u8; 16];
538 cipher_input[..remaining_bytes].copy_from_slice(&associated_data[processed_bytes..]);
539 cipher_input[remaining_bytes] = 0b1000_0000;
540 let cipher_input = Block::from_mut_slice(cipher_input);
541 inplace_xor(cipher_input, &offset_i);
542 self.cipher.encrypt_block(cipher_input);
544 inplace_xor(&mut sum_i, cipher_input);
545 }
546
547 sum_i
548 }
549
550 fn compute_tag(
551 &self,
552 associated_data: &[u8],
553 checksum_m: &mut Block,
554 offset_m: &Block,
555 ) -> Tag<TagSize> {
556 let full_tag = checksum_m;
558 inplace_xor(full_tag, offset_m);
559 inplace_xor(full_tag, &self.ll_dollar);
560 self.cipher.encrypt_block(full_tag);
561 inplace_xor(full_tag, &self.hash(associated_data));
562
563 Tag::clone_from_slice(&full_tag[..TagSize::to_usize()])
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571 use hex_literal::hex;
572
573 #[test]
574 fn double_basic_test() {
575 let zero = Block::from(hex!("00000000000000000000000000000000"));
576 assert_eq!(zero, double(&zero));
577 let one = Block::from(hex!("00000000000000000000000000000001"));
578 let two = Block::from(hex!("00000000000000000000000000000002"));
579 assert_eq!(two, double(&one));
580 }
581
582 #[test]
583 fn rfc7253_key_dependent_constants() {
584 let key = hex!("000102030405060708090A0B0C0D0E0F");
586 let expected_ll_star = Block::from(hex!("C6A13B37878F5B826F4F8162A1C8D879"));
587 let expected_ll_dollar = Block::from(hex!("8D42766F0F1EB704DE9F02C54391B075"));
588 let expected_ll0 = Block::from(hex!("1A84ECDE1E3D6E09BD3E058A8723606D"));
589 let expected_ll1 = Block::from(hex!("3509D9BC3C7ADC137A7C0B150E46C0DA"));
590
591 let cipher = aes::Aes128::new(GenericArray::from_slice(&key));
592 let (ll_star, ll_dollar, ll) = key_dependent_variables(&cipher);
593
594 assert_eq!(ll_star, expected_ll_star);
595 assert_eq!(ll_dollar, expected_ll_dollar);
596 assert_eq!(ll[0], expected_ll0);
597 assert_eq!(ll[1], expected_ll1);
598 }
599
600 #[test]
601 fn rfc7253_nonce_dependent_constants() {
602 let key = hex!("000102030405060708090A0B0C0D0E0F");
604 let nonce = hex!("BBAA9988776655443322110F");
605 let expected_bottom = usize::try_from(15).unwrap();
606 let expected_stretch = hex!("9862B0FDEE4E2DD56DBA6433F0125AA2FAD24D13A063F8B8");
607 let expected_offset_0 = Block::from(hex!("587EF72716EAB6DD3219F8092D517D69"));
608
609 const TAGLEN: u32 = 16;
610
611 let cipher = aes::Aes128::new(GenericArray::from_slice(&key));
612 let (bottom, stretch) = nonce_dependent_variables(&cipher, &Nonce::from(nonce), TAGLEN);
613 let offset_0 = initial_offset(&cipher, &Nonce::from(nonce), TAGLEN);
614
615 assert_eq!(bottom, expected_bottom, "bottom");
616 assert_eq!(stretch, expected_stretch, "stretch");
617 assert_eq!(offset_0, expected_offset_0, "offset");
618 }
619}