1use super::xor_set1;
2use cipher::{
3 AlgorithmName, Block, BlockCipherEncrypt, InnerIvInit, Iv, IvSizeUser, common::InnerUser,
4 typenum::Unsigned,
5};
6use core::fmt;
7
8#[cfg(feature = "zeroize")]
9use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
10
11pub struct BufEncryptor<C>
13where
14 C: BlockCipherEncrypt,
15{
16 cipher: C,
17 iv: Block<C>,
18 pos: usize,
19}
20
21impl<C> BufEncryptor<C>
22where
23 C: BlockCipherEncrypt,
24{
25 pub fn encrypt(&mut self, mut data: &mut [u8]) {
27 let bs = C::BlockSize::USIZE;
28 let n = data.len();
29
30 if n < bs - self.pos {
31 xor_set1(data, &mut self.iv[self.pos..self.pos + n]);
32 self.pos += n;
33 return;
34 }
35
36 let (left, right) = { data }.split_at_mut(bs - self.pos);
37 data = right;
38 let mut iv = self.iv.clone();
39 xor_set1(left, &mut iv[self.pos..]);
40 self.cipher.encrypt_block(&mut iv);
41
42 let mut chunks = data.chunks_exact_mut(bs);
43 for chunk in &mut chunks {
44 xor_set1(chunk, iv.as_mut_slice());
45 self.cipher.encrypt_block(&mut iv);
46 }
47
48 let rem = chunks.into_remainder();
49 xor_set1(rem, iv.as_mut_slice());
50 self.pos = rem.len();
51 self.iv = iv;
52 }
53
54 pub fn get_state(&self) -> (&Block<C>, usize) {
56 (&self.iv, self.pos)
57 }
58
59 pub fn from_state(cipher: C, iv: &Block<C>, pos: usize) -> Self {
61 Self {
62 cipher,
63 iv: iv.clone(),
64 pos,
65 }
66 }
67}
68
69impl<C> InnerUser for BufEncryptor<C>
70where
71 C: BlockCipherEncrypt,
72{
73 type Inner = C;
74}
75
76impl<C> IvSizeUser for BufEncryptor<C>
77where
78 C: BlockCipherEncrypt,
79{
80 type IvSize = C::BlockSize;
81}
82
83impl<C> InnerIvInit for BufEncryptor<C>
84where
85 C: BlockCipherEncrypt,
86{
87 #[inline]
88 fn inner_iv_init(cipher: C, iv: &Iv<Self>) -> Self {
89 let mut iv = iv.clone();
90 cipher.encrypt_block(&mut iv);
91 Self { cipher, iv, pos: 0 }
92 }
93}
94
95impl<C> AlgorithmName for BufEncryptor<C>
96where
97 C: BlockCipherEncrypt + AlgorithmName,
98{
99 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 f.write_str("cfb::BufEncryptor<")?;
101 <C as AlgorithmName>::write_alg_name(f)?;
102 f.write_str(">")
103 }
104}
105
106impl<C> fmt::Debug for BufEncryptor<C>
107where
108 C: BlockCipherEncrypt + AlgorithmName,
109{
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 f.write_str("cfb::BufEncryptor<")?;
112 <C as AlgorithmName>::write_alg_name(f)?;
113 f.write_str("> { ... }")
114 }
115}
116
117impl<C: BlockCipherEncrypt> Drop for BufEncryptor<C> {
118 fn drop(&mut self) {
119 #[cfg(feature = "zeroize")]
120 self.iv.zeroize();
121 }
122}
123
124#[cfg(feature = "zeroize")]
125impl<C: BlockCipherEncrypt + ZeroizeOnDrop> ZeroizeOnDrop for BufEncryptor<C> {}