1use crate::compat;
14use crate::crypto::cipher::{Block, BlockMode};
15use crate::crypto::subtle;
16
17pub struct CBCEncrypter<'a, B: Block> {
20 b: &'a B,
21 block_size: usize,
22 iv: Vec<u8>,
23 tmp: Vec<u8>,
24}
25
26impl<'a, B: Block> CBCEncrypter<'a, B> {
27 pub fn new(b: &'a B, iv: &[u8]) -> Self {
31 let blocksize = b.block_size();
32 if iv.len() != blocksize {
33 panic!("cipher.NewCBCEncrypter: IV length must equal block size");
34 }
35 Self {
36 b,
37 block_size: blocksize,
38 iv: iv.to_vec(),
39 tmp: vec![0; blocksize],
40 }
41 }
42
43 pub fn set_iv(&mut self, iv: &[u8]) {
44 if iv.len() != self.iv.len() {
45 panic!("cipher: incorrect length IV");
46 }
47 compat::copy(&mut self.iv, iv);
48 }
49}
50
51impl<'a, B: Block> BlockMode for CBCEncrypter<'a, B> {
52 fn block_size(&self) -> usize {
53 self.block_size
54 }
55
56 fn crypt_blocks(&mut self, dst: &mut [u8], src: &[u8]) {
57 let block_size = self.block_size;
58 if src.len() % block_size != 0 {
59 panic!("crypto/cipher: input not full blocks");
60 }
61 if dst.len() < src.len() {
62 panic!("crypto/cipher: output smaller than input");
63 }
64 if src.is_empty() {
65 return;
66 }
67
68 let tmp = &mut self.tmp;
69
70 subtle::xor_bytes(tmp, &src[..block_size], &self.iv);
72 self.b.encrypt(&mut dst[..block_size], tmp);
73
74 let mut offset = block_size;
76 let mut iv_offset = 0;
77
78 while offset < src.len() {
79 subtle::xor_bytes(
80 tmp,
81 &src[offset..offset + block_size],
82 &dst[iv_offset..iv_offset + block_size],
83 );
84 self.b.encrypt(&mut dst[offset..offset + block_size], tmp);
85 offset += block_size;
86 iv_offset += block_size;
87 }
88 compat::copy(&mut self.iv, &dst[iv_offset..iv_offset + block_size]);
90 }
91
92 fn crypt_blocks_inplace(&mut self, data: &mut [u8]) {
93 let block_size = self.block_size;
94 if data.len() % block_size != 0 {
95 panic!("crypto/cipher: input not full blocks");
96 }
97 if data.is_empty() {
98 return;
99 }
100
101 let tmp = &mut self.tmp;
102
103 subtle::xor_bytes(tmp, &data[..block_size], &self.iv);
105 self.b.encrypt(&mut data[..block_size], tmp);
106
107 let mut prev = 0;
109 let mut start = block_size;
110 let mut end = start + block_size;
111 while start < data.len() {
112 subtle::xor_bytes(tmp, &data[start..end], &data[prev..start]);
113 self.b.encrypt(&mut data[start..end], tmp);
114 (prev, start, end) = (start, end, end + block_size);
115 }
116 compat::copy(&mut self.iv, &data[data.len() - block_size..]);
118 }
119}
120
121pub struct CBCDecrypter<'a, B: Block> {
124 b: &'a B,
125 block_size: usize,
126 iv: Vec<u8>,
127 tmp: Vec<u8>,
128 tmp_next_iv: Vec<u8>,
129}
130
131impl<'a, B: Block> CBCDecrypter<'a, B> {
132 pub fn new(b: &'a B, iv: &[u8]) -> Self {
136 let blocksize = b.block_size();
137 if iv.len() != blocksize {
138 panic!("cipher.NewCBCDecrypter: IV length must equal block size");
139 }
140 Self {
141 b,
142 block_size: blocksize,
143 iv: iv.to_vec(),
144 tmp: vec![0; blocksize],
145 tmp_next_iv: vec![0; blocksize],
146 }
147 }
148
149 pub fn set_iv(&mut self, iv: &[u8]) {
150 if iv.len() != self.iv.len() {
151 panic!("cipher: incorrect length IV");
152 }
153 compat::copy(&mut self.iv, iv);
154 }
155}
156
157impl<'a, B: Block> BlockMode for CBCDecrypter<'a, B> {
158 fn block_size(&self) -> usize {
159 self.block_size
160 }
161
162 fn crypt_blocks(&mut self, dst: &mut [u8], src: &[u8]) {
163 let block_size = self.block_size;
164 if src.len() % block_size != 0 {
165 panic!("crypto/cipher: input not full blocks");
166 }
167 if dst.len() < src.len() {
168 panic!("crypto/cipher: output smaller than input");
169 }
170 if src.is_empty() {
171 return;
172 }
173
174 let tmp = &mut self.tmp;
175
176 self.b.decrypt(tmp, &src[..block_size]);
179 subtle::xor_bytes(&mut dst[..block_size], tmp, &self.iv);
180
181 let mut prev = 0;
183 let mut start = block_size;
184 let mut end = start + block_size;
185 while start < src.len() {
186 self.b.decrypt(tmp, &src[start..end]);
187 subtle::xor_bytes(&mut dst[start..end], tmp, &src[prev..start]);
188 (prev, start, end) = (start, end, end + block_size);
189 }
190 compat::copy(&mut self.iv, &src[src.len() - block_size..]);
192 }
193
194 fn crypt_blocks_inplace(&mut self, data: &mut [u8]) {
195 let block_size = self.block_size;
196 if data.len() % block_size != 0 {
197 panic!("crypto/cipher: input not full blocks");
198 }
199 if data.is_empty() {
200 return;
201 }
202
203 let tmp = &mut self.tmp;
204
205 let mut end = data.len();
208 let mut start = end - block_size;
209 let mut prev = start - block_size;
210
211 compat::copy(&mut self.tmp_next_iv, &data[start..end]);
213
214 while start > 0 {
216 self.b.decrypt(tmp, &data[start..end]);
217 subtle::xor_bytes(
221 unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr().add(start), block_size) },
222 unsafe { std::slice::from_raw_parts(data.as_ptr().add(prev), block_size) },
223 tmp,
224 );
225 (end, start, prev) = (start, prev, prev.wrapping_sub(block_size));
226 }
227
228 self.b.decrypt(tmp, &data[..block_size]);
230 subtle::xor_bytes(&mut data[..block_size], tmp, &self.iv);
231
232 compat::copy(&mut self.iv, &self.tmp_next_iv);
234 }
235}