1use crate::traits::{BlockMode, IvState};
2use crate::utils::{get_par_blocks, xor, Block, ParBlocks};
3use block_padding::Padding;
4use cipher::generic_array::{typenum::Unsigned, GenericArray};
5use cipher::{BlockCipher, BlockDecrypt, BlockEncrypt};
6use core::marker::PhantomData;
7
8#[derive(Clone)]
12pub struct Cbc<C: BlockCipher + BlockEncrypt + BlockDecrypt, P: Padding> {
13 cipher: C,
14 iv: GenericArray<u8, C::BlockSize>,
15 _p: PhantomData<P>,
16}
17
18impl<C, P> Cbc<C, P>
19where
20 C: BlockCipher + BlockEncrypt + BlockDecrypt,
21 P: Padding,
22{
23 #[inline(always)]
24 fn single_blocks_decrypt(&mut self, blocks: &mut [Block<C>]) {
25 let mut iv = self.iv.clone();
26 for block in blocks {
27 let block_copy = block.clone();
28 self.cipher.decrypt_block(block);
29 xor(block, iv.as_slice());
30 iv = block_copy;
31 }
32 self.iv = iv;
33 }
34}
35
36impl<C, P> BlockMode<C, P> for Cbc<C, P>
37where
38 C: BlockCipher + BlockEncrypt + BlockDecrypt,
39 P: Padding,
40{
41 type IvSize = C::BlockSize;
42
43 fn new(cipher: C, iv: &Block<C>) -> Self {
44 Self {
45 cipher,
46 iv: iv.clone(),
47 _p: Default::default(),
48 }
49 }
50
51 fn encrypt_blocks(&mut self, blocks: &mut [Block<C>]) {
52 self.iv = {
53 let mut iv = &self.iv;
54 for block in blocks {
55 xor(block, &iv);
56 self.cipher.encrypt_block(block);
57 iv = block;
58 }
59 iv.clone()
60 };
61 }
62
63 fn decrypt_blocks(&mut self, blocks: &mut [Block<C>]) {
64 let pbn = C::ParBlocks::to_usize();
65 if pbn != 1 {
66 let (par_blocks, leftover) = get_par_blocks::<C>(blocks);
67 let mut iv_buf = ParBlocks::<C>::default();
68 iv_buf[0] = self.iv.clone();
69 for pb in par_blocks {
70 iv_buf[1..].clone_from_slice(&pb[..pbn - 1]);
71 let next_iv = pb[pbn - 1].clone();
72 self.cipher.decrypt_blocks(pb);
73 pb.iter_mut()
74 .zip(iv_buf.iter())
75 .for_each(|(a, b)| xor(a, b));
76 iv_buf[0] = next_iv;
77 }
78 self.iv = iv_buf[0].clone();
79 self.single_blocks_decrypt(leftover);
80 } else {
81 self.single_blocks_decrypt(blocks);
82 }
83 }
84}
85
86impl<C, P> IvState<C, P> for Cbc<C, P>
87where
88 C: BlockCipher + BlockEncrypt + BlockDecrypt,
89 P: Padding,
90{
91 fn iv_state(&self) -> GenericArray<u8, <Self as BlockMode<C, P>>::IvSize> {
92 self.iv.clone()
93 }
94}